add search list in block menu

This commit is contained in:
Abhimanyu Yadav
2025-05-18 21:10:19 +05:30
parent 4af0aedebd
commit bc08012771
20 changed files with 535 additions and 88 deletions

View File

@@ -18,8 +18,11 @@ const BlockMenuContent: React.FC = () => {
<Separator className="h-[1px] w-full text-zinc-300" />
{/* Content */}
{/* BLOCK MENU TODO : search after 3 characters */}
{searchQuery ? <BlockMenuSearch /> : <BlockMenuDefault />}
{searchQuery ? (
<BlockMenuSearch searchQuery={searchQuery} />
) : (
<BlockMenuDefault />
)}
</div>
);
};

View File

@@ -16,7 +16,12 @@ const BlockMenuSearchBar: React.FC<BlockMenuSearchBarProps> = ({
}) => {
const inputRef = useRef(null);
return (
<div className="flex min-h-[3.5625rem] items-center gap-2.5 px-4">
<div
className={cn(
"flex min-h-[3.5625rem] items-center gap-2.5 px-4",
className,
)}
>
<Search className="h-6 w-6 text-zinc-700" strokeWidth={2} />
<Input
ref={inputRef}

View File

@@ -1,4 +1,5 @@
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import { cn } from "@/lib/utils";
import { Plus } from "lucide-react";
import Image from "next/image";
@@ -10,7 +11,11 @@ interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
icon_url?: string;
}
const IntegrationBlock: React.FC<Props> = ({
interface IntegrationBlockComponent extends React.FC<Props> {
Skeleton: React.FC<{ className?: string }>;
}
const IntegrationBlock: IntegrationBlockComponent = ({
title,
icon_url,
description,
@@ -61,4 +66,24 @@ const IntegrationBlock: React.FC<Props> = ({
);
};
const IntegrationBlockSkeleton = ({ className }: { className?: string }) => {
return (
<Skeleton
className={cn(
"flex h-16 w-full min-w-[7.5rem] animate-pulse items-center justify-start gap-3 rounded-[0.75rem] bg-zinc-100 px-[0.875rem] py-[0.625rem]",
className,
)}
>
<Skeleton className="h-[2.625rem] w-[2.625rem] rounded-[0.5rem] bg-zinc-200" />
<div className="flex flex-1 flex-col items-start gap-0.5">
<Skeleton className="h-[1.375rem] w-24 rounded bg-zinc-200" />
<Skeleton className="h-5 w-32 rounded bg-zinc-200" />
</div>
<Skeleton className="h-7 w-7 rounded-[0.5rem] bg-zinc-200" />
</Skeleton>
);
};
IntegrationBlock.Skeleton = IntegrationBlockSkeleton;
export default IntegrationBlock;

View File

@@ -7,11 +7,11 @@ const ActionBlocksContent: React.FC = () => {
const [blocks, setBlocks] = useState<BlockListType[]>([]);
const [loading, setLoading] = useState(true);
// Update Block Menu fetching
useEffect(() => {
const fetchBlocks = async () => {
setLoading(true);
try {
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 1000));
setBlocks(actionBlocksListData);
} catch (error) {

View File

@@ -1,5 +1,3 @@
// BLOCK MENU TODO: Currently I have hide the scrollbar, but need to add better designed custom scroller
import React, { useState, useEffect, Fragment } from "react";
import Block from "../Block";
import { Button } from "@/components/ui/button";
@@ -7,7 +5,6 @@ import { Separator } from "@/components/ui/separator";
import { allBlocksDataWithCategories } from "../../testing_data";
import { Skeleton } from "@/components/ui/skeleton";
// These are Temporary type, need to change it in future
type BlockItem = {
title: string;
description: string;
@@ -23,6 +20,7 @@ const AllBlocksContent: React.FC = () => {
const [categories, setCategories] = useState<BlockCategory[]>([]);
const [loading, setLoading] = useState(true);
// Update Block Menu fetching
useEffect(() => {
const fetchBlocks = async () => {
setLoading(true);
@@ -41,7 +39,7 @@ const AllBlocksContent: React.FC = () => {
{[0, 1, 3].map((categoryIndex) => (
<Fragment key={categoryIndex}>
{categoryIndex > 0 && (
<Skeleton className="h-[1px] w-full text-zinc-100" />
<Skeleton className="my-4 h-[1px] w-full text-zinc-100" />
)}
{[0, 1, 2].map((blockIndex) => (
<Block.Skeleton key={`${categoryIndex}-${blockIndex}`} />
@@ -53,7 +51,7 @@ const AllBlocksContent: React.FC = () => {
}
return (
<div className="scrollbar-thumb-rounded h-full overflow-y-scroll pt-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200">
<div className="scrollbar-thumb-rounded scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200 h-full overflow-y-scroll pt-4">
<div className="w-full space-y-3 px-4 pb-4">
{categories.map((category, index) => (
<Fragment key={category.name}>

View File

@@ -1,5 +1,3 @@
// BLOCK MENU TODO: Fix scrollbar in all states
import React, { useState } from "react";
import BlockMenuSidebar from "./BlockMenuSidebar";
import { Separator } from "@/components/ui/separator";

View File

@@ -13,10 +13,7 @@ const BlockMenuSidebar: React.FC<BlockMenuSidebarProps> = ({
setDefaultState,
setIntegration,
}) => {
// BLOCK MENU TODO: We need to fetch the number of Blocks/Integrations/Agents when opening the menu.
// Alternatively, this might depend on the strategy we plan in the future.
// We'll add a loading state based on the future plan.
// Update Block Menu fetching
return (
<div className="space-y-2 p-4">
<MenuItem

View File

@@ -8,10 +8,10 @@ const InputBlocksContent: React.FC = () => {
const [loading, setLoading] = useState(true);
useEffect(() => {
// Update Block Menu fetching
const fetchBlocks = async () => {
setLoading(true);
try {
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 1000));
setBlocks(inputBlocksListData);
} catch (error) {

View File

@@ -1,6 +1,16 @@
import { Button } from "@/components/ui/button";
import React from "react";
import React, { useState, useEffect } from "react";
import IntegrationBlock from "../IntegrationBlock";
import {
integrationBlocksData,
integrationsListData,
} from "../../testing_data";
export interface IntegrationBlockData {
title: string;
description: string;
icon_url: string;
}
interface IntegrationBlocksProps {
integration: string;
@@ -11,6 +21,28 @@ const IntegrationBlocks: React.FC<IntegrationBlocksProps> = ({
integration,
setIntegration,
}) => {
const [blocks, setBlocks] = useState<IntegrationBlockData[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
// Update Block Menu fetching
useEffect(() => {
if (integration) {
setIsLoading(true);
setTimeout(() => {
const foundBlocks = integrationBlocksData[integration] || [];
setBlocks(foundBlocks);
setIsLoading(false);
}, 800);
}
}, [integration]);
const getBlockCount = (): number => {
const integrationData = integrationsListData.find(
(item) => item.title === integration,
);
return integrationData?.number_of_blocks || 0;
};
return (
<div className="space-y-2.5">
<div className="flex items-center justify-between">
@@ -32,56 +64,28 @@ const IntegrationBlocks: React.FC<IntegrationBlocksProps> = ({
</p>
</div>
<span className="flex h-[1.375rem] w-[1.6875rem] items-center justify-center rounded-[1.25rem] bg-[#f0f0f0] p-1.5 font-sans text-sm leading-[1.375rem] text-zinc-500 group-disabled:text-zinc-400">
{13}
{getBlockCount()}
</span>
</div>
{integration == "Twitter Blocks" && (
<div className="space-y-3">
<IntegrationBlock
title={`${integration}: Post tweet`}
description="Post tweet on twitter"
icon_url="/integrations/x.png"
/>
<IntegrationBlock
title={`${integration}: Delete tweet`}
description="Delete tweet on twitter"
icon_url="/integrations/x.png"
/>
<IntegrationBlock
title={`${integration}: Update tweet`}
description="Update tweet on twitter"
icon_url="/integrations/x.png"
/>
<IntegrationBlock
title={`${integration}: Retweet tweet`}
description="Retweet tweet on twitter"
icon_url="/integrations/x.png"
/>
</div>
)}
{integration == "Discord Blocks" && (
{isLoading ? (
<div className="space-y-3">
<IntegrationBlock
title={`${integration}: Create`}
description="Create message on discord"
icon_url="/integrations/discord.png"
/>
<IntegrationBlock
title={`${integration}: Delete`}
description="Delete message on discord"
icon_url="/integrations/discord.png"
/>
<IntegrationBlock
title={`${integration}: Update`}
description="Update message on discord"
icon_url="/integrations/discord.png"
/>
<IntegrationBlock
title={`${integration}: Read`}
description="Read message on discord"
icon_url="/integrations/discord.png"
/>
{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.title}
description={block.description}
icon_url={block.icon_url}
/>
))}
</div>
)}
</div>

View File

@@ -19,12 +19,11 @@ const IntegrationList: React.FC<IntegrationListProps> = ({
const [integrations, setIntegrations] = useState<IntegrationData[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
// Update Block Menu fetching
useEffect(() => {
// Mock API call to fetch integrations
const fetchIntegrations = async () => {
setIsLoading(true);
try {
// Simulate network delay
await new Promise((resolve) => setTimeout(resolve, 1000));
setIntegrations(integrationsListData);

View File

@@ -11,9 +11,8 @@ const IntegrationsContent: React.FC<IntegrationsContentProps> = ({
integration,
setIntegration,
}) => {
// I am currently comparing the integration with names, in future maybe using ids
return (
<div className="scrollbar-thumb-rounded h-full overflow-y-scroll pt-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200">
<div className="scrollbar-thumb-rounded scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200 h-full overflow-y-scroll pt-4">
<div className="w-full px-4 pb-4">
{integration == "" ? (
<IntegrationList setIntegration={setIntegration} />

View File

@@ -14,6 +14,7 @@ const MarketplaceAgentsContent: React.FC = () => {
const [agents, setAgents] = useState<MarketplaceAgent[]>([]);
const [loading, setLoading] = useState<boolean>(true);
// Update Block Menu fetching
useEffect(() => {
const fetchAgents = async () => {
try {
@@ -41,7 +42,7 @@ const MarketplaceAgentsContent: React.FC = () => {
}
return (
<div className="scrollbar-thumb-rounded h-full overflow-y-scroll pt-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200">
<div className="scrollbar-thumb-rounded scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200 h-full overflow-y-scroll pt-4">
<div className="w-full space-y-3 px-4 pb-4">
{agents.map((agent) => (
<MarketplaceAgentBlock

View File

@@ -14,6 +14,7 @@ const MyAgentsContent: React.FC = () => {
const [agents, setAgents] = useState<UserAgent[]>([]);
const [loading, setLoading] = useState<boolean>(true);
// Update Block Menu fetching
useEffect(() => {
const fetchAgents = async () => {
try {
@@ -41,7 +42,7 @@ const MyAgentsContent: React.FC = () => {
}
return (
<div className="scrollbar-thumb-rounded h-full overflow-y-scroll pt-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200">
<div className="scrollbar-thumb-rounded scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200 h-full overflow-y-scroll pt-4">
<div className="w-full space-y-3 px-4 pb-4">
{agents.map((agent) => (
<UGCAgentBlock

View File

@@ -7,11 +7,11 @@ const OutputBlocksContent: React.FC = () => {
const [blocks, setBlocks] = useState<BlockListType[]>([]);
const [loading, setLoading] = useState(true);
// Update Block Menu fetching
useEffect(() => {
const fetchBlocks = async () => {
setLoading(true);
try {
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 1000));
setBlocks(outputBlocksListData);
} catch (error) {

View File

@@ -26,10 +26,10 @@ const SuggestionContent: React.FC<SuggestionContentProps> = ({
{ title: string; description: string }[] | null
>(null);
// Update Block Menu fetching
useEffect(() => {
const fetchData = async () => {
try {
// Create fetch functions that return their respective data
const fetchRecentSearches = async (): Promise<string[]> => {
await new Promise((resolve) => setTimeout(resolve, 300));
return recentSearchesData;
@@ -49,7 +49,6 @@ const SuggestionContent: React.FC<SuggestionContentProps> = ({
return topBlocksData;
};
// Fetch all data simultaneously using Promise.all
const [
recentSearchesDataFetched,
integrationsDataFetched,
@@ -72,14 +71,14 @@ const SuggestionContent: React.FC<SuggestionContentProps> = ({
}, []);
return (
<div className="scrollbar-thumb-rounded h-full overflow-y-scroll pt-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200">
<div className="scrollbar-thumb-rounded scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200 h-full overflow-y-scroll pt-4">
<div className="w-full space-y-6 pb-4">
{/* Recent Searches */}
<div className="space-y-2.5">
<p className="px-4 font-sans text-sm font-medium leading-[1.375rem] text-zinc-800">
Recent searches
</p>
<div className="flex flex-nowrap gap-2 overflow-x-auto scrollbar-hide">
<div className="scrollbar-hide flex flex-nowrap gap-2 overflow-x-auto">
{recentSearches
? recentSearches.map((search, index) => (
<SearchHistoryChip

View File

@@ -0,0 +1,60 @@
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { Plus } from "lucide-react";
import { ButtonHTMLAttributes } from "react";
interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
title?: string;
description?: string;
ai_name?: string;
}
const AiBlock: React.FC<Props> = ({
title,
description,
className,
ai_name,
...rest
}) => {
return (
<Button
className={cn(
"group flex h-[5.625rem] w-full min-w-[7.5rem] items-center justify-start space-x-3 whitespace-normal rounded-[0.75rem] bg-zinc-50 px-[0.875rem] py-[0.625rem] text-start shadow-none hover:bg-zinc-100 focus:ring-0 active:border active:border-zinc-300 active:bg-zinc-100 disabled:pointer-events-none",
)}
{...rest}
>
<div className="flex flex-1 flex-col items-start gap-1.5">
<span
className={cn(
"line-clamp-1 font-sans text-sm font-medium leading-[1.375rem] text-zinc-700 group-disabled:text-zinc-400",
)}
>
{title}
</span>
<span
className={cn(
"line-clamp-1 font-sans text-xs font-normal leading-5 text-zinc-500 group-disabled:text-zinc-400",
)}
>
{description}
</span>
<span
className={cn(
"rounded-[0.75rem] bg-zinc-200 px-[0.5rem] font-sans text-xs leading-[1.25rem] text-zinc-500",
)}
>
Supports {ai_name}
</span>
</div>
<div
className={cn(
"flex h-7 w-7 items-center justify-center rounded-[0.5rem] bg-zinc-700 group-disabled:bg-zinc-400",
)}
>
<Plus className="h-5 w-5 text-zinc-50" strokeWidth={2} />
</div>
</Button>
);
};
export default AiBlock;

View File

@@ -1,9 +1,14 @@
import React from "react";
import FiltersList from "./FiltersList";
import SearchList from "./SearchList.";
const BlockMenuSearch: React.FC = () => {
const BlockMenuSearch: React.FC<{ searchQuery: string }> = ({
searchQuery,
}) => {
return (
<div className="p-4">
<h2>Filter Block Menu</h2>
<div className="scrollbar-thumb-rounded scrollbar-thin scrollbar-track-transparent scrollbar-thumb-zinc-200 h-full space-y-4 overflow-y-scroll p-4">
<FiltersList />
<SearchList searchQuery={searchQuery} />
</div>
);
};

View File

@@ -0,0 +1,18 @@
import FilterChip from "../FilterChip";
const FiltersList = () => {
return (
<div className="space-x-3">
<FilterChip name="All filters" />
{/* Created by filters */}
{/* Fixed filters */}
<FilterChip name="Blocks" />
<FilterChip name="Integrations" />
<FilterChip name="Marketplace agents" />
<FilterChip name="My agents" />
</div>
);
};
export default FiltersList;

View File

@@ -0,0 +1,153 @@
import { marketplaceAgentData, searchingData } from "../../testing_data";
import { useEffect, useState } from "react";
import MarketplaceAgentBlock from "../MarketplaceAgentBlock";
import Block from "../Block";
import UGCAgentBlock from "../UGCAgentBlock";
import AiBlock from "./AiBlock";
import IntegrationBlock from "../IntegrationBlock";
interface BaseSearchItem {
type: "marketing_agent" | "integration_block" | "block" | "my_agent" | "ai";
}
interface MarketingAgentItem extends BaseSearchItem {
type: "marketing_agent";
title: string;
image_url: string;
creator_name: string;
number_of_runs: number;
}
interface AIItem extends BaseSearchItem {
type: "ai";
title: string;
description: string;
ai_name: string;
}
interface BlockItem extends BaseSearchItem {
type: "block";
title: string;
description: string;
}
interface IntegrationItem extends BaseSearchItem {
type: "integration_block";
title: string;
description: string;
icon_url: string;
number_of_blocks: number;
}
interface MyAgentItem extends BaseSearchItem {
type: "my_agent";
title: string;
image_url: string;
edited_time: string;
version: number;
}
export type SearchItem =
| MarketingAgentItem
| AIItem
| BlockItem
| IntegrationItem
| MyAgentItem;
const SearchList = ({ searchQuery }: { searchQuery: string }) => {
const [searchData, setSearchData] = useState<SearchItem[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
try {
await new Promise((resolve) => setTimeout(resolve, 1500));
setSearchData(searchingData as SearchItem[]);
} catch (error) {
console.error("Error fetching search data:", error);
} finally {
setIsLoading(false);
}
};
fetchData();
}, [searchQuery]);
if (isLoading) {
return (
<div className="space-y-2.5">
<p className="font-sans text-sm font-medium leading-[1.375rem] text-zinc-800">
Search results
</p>
{Array(6)
.fill(0)
.map(() => (
<Block.Skeleton />
))}
</div>
);
}
return (
<div className="space-y-2.5">
<p className="font-sans text-sm font-medium leading-[1.375rem] text-zinc-800">
Search results
</p>
{searchData.map((item: SearchItem, index: number) => {
switch (item.type) {
case "marketing_agent":
return (
<MarketplaceAgentBlock
key={index}
title={item.title}
image_url={item.image_url}
creator_name={item.creator_name}
number_of_runs={item.number_of_runs}
/>
);
case "block":
return (
<Block
key={index}
title={item.title}
description={item.description}
/>
);
case "integration_block":
return (
<IntegrationBlock
key={index}
title={item.title}
description={item.description}
icon_url={item.icon_url}
/>
);
case "my_agent":
return (
<UGCAgentBlock
key={index}
title={item.title}
image_url={item.image_url}
version={item.version}
edited_time={item.edited_time}
/>
);
case "ai":
return (
<AiBlock
key={index}
title={item.title}
description={item.description}
ai_name={item.ai_name}
/>
);
default:
return null;
}
})}
</div>
);
};
export default SearchList;

View File

@@ -2,9 +2,11 @@
import { BlockCategory } from "./block-menu/default/AllBlocksContent";
import { BlockListType } from "./block-menu/default/BlockMenuDefaultContent";
import { IntegrationBlockData } from "./block-menu/default/IntegrationBlocks";
import { IntegrationData } from "./block-menu/default/IntegrationList";
import { MarketplaceAgent } from "./block-menu/default/MarketplaceAgentsContent";
import { UserAgent } from "./block-menu/default/MyAgentsContent";
import { SearchItem } from "./block-menu/search-and-filter/SearchList.";
// Suggestion
@@ -207,44 +209,44 @@ export const outputBlocksListData: BlockListType[] = [
export const integrationsListData: IntegrationData[] = [
{
title: "Twitter Blocks",
title: "Twitter",
icon_url: "/integrations/x.png",
description:
"All twitter blocks, It has everthing to interact with twitter",
number_of_blocks: 10,
number_of_blocks: 4,
},
{
title: "Discord Blocks",
title: "Discord",
icon_url: "/integrations/discord.png",
description:
"All Discord blocks, It has everthing to interact with discord",
number_of_blocks: 14,
number_of_blocks: 4,
},
{
title: "Github Blocks",
title: "Github",
icon_url: "/integrations/github.png",
description: "All Github blocks, It has everthing to interact with github",
number_of_blocks: 4,
},
{
title: "Hubspot Blocks",
title: "Hubspot",
icon_url: "/integrations/hubspot.png",
description:
"All Hubspot blocks, It has everthing to interact with Hubspot",
number_of_blocks: 2,
},
{
title: "Medium Blocks",
title: "Medium",
icon_url: "/integrations/medium.png",
description: "All Medium blocks, It has everything to interact with Medium",
number_of_blocks: 6,
number_of_blocks: 4,
},
{
title: "Todoist Blocks",
title: "Todoist",
icon_url: "/integrations/todoist.png",
description:
"All Todoist blocks, It has everything to interact with Todoist",
number_of_blocks: 8,
number_of_blocks: 4,
},
];
@@ -358,3 +360,183 @@ export const myAgentData: UserAgent[] = [
image_url: "/placeholder.png",
},
];
export const integrationBlocksData: Record<string, IntegrationBlockData[]> = {
Twitter: [
{
title: "Twitter Blocks: Post tweet",
description: "Post tweet on twitter",
icon_url: "/integrations/x.png",
},
{
title: "Twitter Blocks: Delete tweet",
description: "Delete tweet on twitter",
icon_url: "/integrations/x.png",
},
{
title: "Twitter Blocks: Update tweet",
description: "Update tweet on twitter",
icon_url: "/integrations/x.png",
},
{
title: "Twitter Blocks: Retweet tweet",
description: "Retweet tweet on twitter",
icon_url: "/integrations/x.png",
},
],
Discord: [
{
title: "Discord Blocks: Create",
description: "Create message on discord",
icon_url: "/integrations/discord.png",
},
{
title: "Discord Blocks: Delete",
description: "Delete message on discord",
icon_url: "/integrations/discord.png",
},
{
title: "Discord Blocks: Update",
description: "Update message on discord",
icon_url: "/integrations/discord.png",
},
{
title: "Discord Blocks: Read",
description: "Read message on discord",
icon_url: "/integrations/discord.png",
},
],
Github: [
{
title: "Github Blocks: Create PR",
description: "Create pull request on github",
icon_url: "/integrations/github.png",
},
{
title: "Github Blocks: Merge PR",
description: "Merge pull request on github",
icon_url: "/integrations/github.png",
},
],
Hubspot: [
{
title: "Hubspot Blocks: Create Contact",
description: "Create contact on hubspot",
icon_url: "/integrations/hubspot.png",
},
{
title: "Hubspot Blocks: Update Contact",
description: "Update contact on hubspot",
icon_url: "/integrations/hubspot.png",
},
],
Medium: [
{
title: "Medium Blocks: Post Article",
description: "Post article on medium",
icon_url: "/integrations/medium.png",
},
{
title: "Medium Blocks: Delete Article",
description: "Delete article on medium",
icon_url: "/integrations/medium.png",
},
],
Todoist: [
{
title: "Todoist Blocks: Create Task",
description: "Create task on todoist",
icon_url: "/integrations/todoist.png",
},
{
title: "Todoist Blocks: Complete Task",
description: "Complete task on todoist",
icon_url: "/integrations/todoist.png",
},
],
};
export const searchingData: SearchItem[] = [
{
type: "marketing_agent" as const,
title: marketplaceAgentData[0].title,
image_url: marketplaceAgentData[0].image_url,
creator_name: marketplaceAgentData[0].creator_name,
number_of_runs: marketplaceAgentData[0].number_of_runs,
},
{
type: "ai",
title: "Natural Language Processing",
description: "Enables your agent to chat with users in natural language.",
ai_name: "Claude 3.5 Sonnet",
},
{
type: "integration_block" as const,
title: integrationsListData[0].title,
description: integrationsListData[0].description,
icon_url: integrationsListData[0].icon_url,
number_of_blocks: integrationsListData[0].number_of_blocks,
},
{
type: "marketing_agent" as const,
title: marketplaceAgentData[1].title,
image_url: marketplaceAgentData[1].image_url,
creator_name: marketplaceAgentData[1].creator_name,
number_of_runs: marketplaceAgentData[1].number_of_runs,
},
{
type: "block" as const,
title: topBlocksData[0].title,
description: topBlocksData[0].description,
},
{
type: "my_agent" as const,
title: myAgentData[0].title,
image_url: myAgentData[0].image_url,
edited_time: myAgentData[0].edited_time,
version: myAgentData[0].version,
},
{
type: "ai",
title: "Sentiment Analysis",
description:
"Analyzes the sentiment of user messages to respond appropriately.",
ai_name: "Claude 3.5 Sonnet",
},
{
type: "block" as const,
title: topBlocksData[1].title,
description: topBlocksData[1].description,
},
{
type: "marketing_agent" as const,
title: marketplaceAgentData[2].title,
image_url: marketplaceAgentData[2].image_url,
creator_name: marketplaceAgentData[2].creator_name,
number_of_runs: marketplaceAgentData[2].number_of_runs,
},
{
type: "integration_block" as const,
title: integrationsListData[1].title,
description: integrationsListData[1].description,
icon_url: integrationsListData[1].icon_url,
number_of_blocks: integrationsListData[1].number_of_blocks,
},
{
type: "my_agent" as const,
title: myAgentData[1].title,
image_url: myAgentData[1].image_url,
edited_time: myAgentData[1].edited_time,
version: myAgentData[1].version,
},
];