Skip to content

Commit 5c25296

Browse files
authored
feat(tools): add available workers count to tools API and UI (#304)
1 parent f13f94d commit 5c25296

File tree

12 files changed

+3056
-2959
lines changed

12 files changed

+3056
-2959
lines changed

console/src/pages/tools/components/marketplace.tsx

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,28 @@
1-
import { useWorkspaceSelector } from "@/hooks/useWorkspaceSelector";
2-
import { ToolsControllerGetManyToolsCategory, ToolsControllerGetManyToolsType, useToolsControllerGetManyTools } from "@/services/apis/gen/queries";
3-
import { LayoutGrid } from "lucide-react";
4-
import { useSearchParams } from "react-router-dom";
5-
import ToolsList from "../tools-list";
6-
import ToolInstallButton from "./tool-install-button";
1+
import { useWorkspaceSelector } from '@/hooks/useWorkspaceSelector';
2+
import { useToolsControllerGetManyTools } from '@/services/apis/gen/queries';
3+
import { LayoutGrid } from 'lucide-react';
4+
import ToolsList from '../tools-list';
5+
import ToolInstallButton from './tool-install-button';
76

87
const Marketplace = () => {
98
const { selectedWorkspace } = useWorkspaceSelector();
10-
const [searchParams] = useSearchParams();
11-
const category = searchParams.get("category") ?? "";
12-
const { data, isLoading } = useToolsControllerGetManyTools({
13-
type: ToolsControllerGetManyToolsType.provider,
14-
category: category as ToolsControllerGetManyToolsCategory,
15-
}, {
16-
query: {
17-
queryKey: [selectedWorkspace, category]
18-
}
19-
});
9+
const { data, isLoading } = useToolsControllerGetManyTools(
10+
{},
11+
{
12+
query: {
13+
queryKey: [selectedWorkspace],
14+
},
15+
},
16+
);
2017
return (
21-
<div className="mt-8">
18+
<div>
2219
<ToolsList
2320
data={data?.data}
2421
isLoading={isLoading}
2522
icon={<LayoutGrid className="w-6 h-6" />}
2623
title="Marketplace"
2724
renderButton={(tool) => (
28-
<ToolInstallButton
29-
tool={tool}
30-
workspaceId={selectedWorkspace}
31-
/>
25+
<ToolInstallButton tool={tool} workspaceId={selectedWorkspace} />
3226
)}
3327
/>
3428
</div>
Lines changed: 94 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,39 @@
11
import { Badge } from '@/components/ui/badge';
22
import { Card, CardContent, CardTitle } from '@/components/ui/card';
33
import Image from '@/components/ui/image';
4-
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
4+
import {
5+
Tooltip,
6+
TooltipContent,
7+
TooltipProvider,
8+
TooltipTrigger,
9+
} from '@/components/ui/tooltip';
510
import { useNavigateWithParams } from '@/hooks/useNavigateWithParams';
611
import type { Tool } from '@/services/apis/gen/queries';
712
import { Verified } from 'lucide-react';
813
import React from 'react';
914

1015
interface ToolCardProps {
11-
tool: Tool;
12-
button?: React.ReactNode;
16+
tool: Tool;
17+
button?: React.ReactNode;
1318
}
1419

1520
const ToolCard = ({ tool, button }: ToolCardProps) => {
16-
const navigateWithParams = useNavigateWithParams()
17-
const handleCardClick = (e: React.MouseEvent) => {
18-
// Don't navigate if clicking on the button
19-
if ((e.target as HTMLElement).closest('button')) {
20-
return;
21-
}
22-
navigateWithParams(`/tools/${tool.id}`);
23-
};
21+
const navigateWithParams = useNavigateWithParams();
22+
const handleCardClick = (e: React.MouseEvent) => {
23+
// Don't navigate if clicking on the button
24+
if ((e.target as HTMLElement).closest('button')) {
25+
return;
26+
}
27+
navigateWithParams(`/tools/${tool.id}`);
28+
};
2429

25-
return (
26-
<Card
27-
key={tool.id}
28-
className="flex flex-col overflow-hidden cursor-pointer transition-all duration-200 hover:shadow-md"
29-
onClick={handleCardClick}
30-
>
31-
{/* <div className="w-full bg-white p-4 flex justify-center items-center transition-colors duration-200 hover:bg-gray-100 min-h-[80px]">
30+
return (
31+
<Card
32+
key={tool.id}
33+
className="flex flex-col overflow-hidden cursor-pointer transition-all duration-200 hover:shadow-md"
34+
onClick={handleCardClick}
35+
>
36+
{/* <div className="w-full bg-white p-4 flex justify-center items-center transition-colors duration-200 hover:bg-gray-100 min-h-[80px]">
3237
{tool.logoUrl ? (
3338
<img
3439
src={tool.logoUrl}
@@ -42,62 +47,80 @@ const ToolCard = ({ tool, button }: ToolCardProps) => {
4247
)}
4348
</div> */}
4449

45-
<CardContent className="flex flex-col space-y-3">
46-
<div className="flex items-center justify-between">
47-
<div className="flex flex-col">
48-
<div className="flex items-center gap-3">
49-
<Image url={tool?.logoUrl} width={70} height={70} className='rounded-2xl' />
50-
<div className='flex items-center gap-2'>
51-
<CardTitle className="text-left text-lg">{tool.name}</CardTitle>
52-
{tool.isOfficialSupport && (
53-
<TooltipProvider>
54-
<Tooltip>
55-
<TooltipTrigger asChild>
56-
<Verified className="w-4 h-4 text-blue-500" />
57-
</TooltipTrigger>
58-
<TooltipContent>
59-
<p>Official Support</p>
60-
</TooltipContent>
61-
</Tooltip>
62-
</TooltipProvider>
63-
)}
64-
</div>
65-
</div>
66-
</div>
67-
<div className="flex-shrink-0">
68-
{button}
69-
</div>
70-
</div>
50+
<CardContent className="flex flex-col space-y-3">
51+
<div className="flex items-center justify-between">
52+
<div className="flex flex-col">
53+
<div className="flex items-center gap-3">
54+
<Image
55+
url={tool?.logoUrl}
56+
width={70}
57+
height={70}
58+
className="rounded-2xl"
59+
/>
60+
<div>
7161
<div className="flex items-center gap-2">
72-
{/* <Badge variant="secondary" className="text-xs font-normal px-2 py-1">
73-
{tool.version || 'N/A'}
74-
</Badge> */}
75-
<Badge variant="secondary" className="text-xs font-normal px-2 py-1">
76-
{tool.category
77-
? tool.category
78-
.split('_')
79-
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
80-
.join(' ')
81-
: 'N/A'}
82-
</Badge>
83-
</div>
84-
<TooltipProvider>
85-
<Tooltip>
62+
<CardTitle className="text-left text-lg">
63+
{tool.name}
64+
</CardTitle>
65+
{tool.isOfficialSupport && (
66+
<TooltipProvider>
67+
<Tooltip>
8668
<TooltipTrigger asChild>
87-
<p className="text-sm text-muted-foreground line-clamp-3">
88-
{tool.description || 'No description available.'}
89-
</p>
69+
<Verified className="w-4 h-4 text-blue-500" />
9070
</TooltipTrigger>
91-
<TooltipContent side="bottom" className="w-full max-w-[300px] p-2">
92-
<p className="text-sm">
93-
{tool.description || 'No description available.'}
94-
</p>
71+
<TooltipContent>
72+
<p>Official Support</p>
9573
</TooltipContent>
96-
</Tooltip>
97-
</TooltipProvider>
98-
</CardContent>
99-
</Card>
100-
);
74+
</Tooltip>
75+
</TooltipProvider>
76+
)}
77+
</div>
78+
<div className="font-semibold">
79+
{tool.availableWorkersCount !== undefined &&
80+
tool.availableWorkersCount > 0 ? (
81+
<span className="text-sm text-green-600">
82+
{tool.availableWorkersCount} worker
83+
{tool.availableWorkersCount === 1 ? '' : 's'}
84+
</span>
85+
) : (
86+
<span className="text-sm text-gray-500">Offline</span>
87+
)}
88+
</div>
89+
</div>
90+
</div>
91+
</div>
92+
<div className="shrink-0">{button}</div>
93+
</div>
94+
<div className="flex items-center gap-2">
95+
{/* <Badge variant="secondary" className="text-xs font-normal px-2 py-1">
96+
{tool.version || 'N/A'}
97+
</Badge> */}
98+
<Badge variant="secondary" className="text-xs font-normal px-2 py-1">
99+
{tool.category
100+
? tool.category
101+
.split('_')
102+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
103+
.join(' ')
104+
: 'N/A'}
105+
</Badge>
106+
</div>
107+
<TooltipProvider>
108+
<Tooltip>
109+
<TooltipTrigger asChild>
110+
<p className="text-sm text-muted-foreground line-clamp-3">
111+
{tool.description || 'No description available.'}
112+
</p>
113+
</TooltipTrigger>
114+
<TooltipContent side="bottom" className="w-full max-w-75 p-2">
115+
<p className="text-sm">
116+
{tool.description || 'No description available.'}
117+
</p>
118+
</TooltipContent>
119+
</Tooltip>
120+
</TooltipProvider>
121+
</CardContent>
122+
</Card>
123+
);
101124
};
102125

103-
export default ToolCard;
126+
export default ToolCard;
Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import type { Tool } from "@/services/apis/gen/queries";
2-
import React, { type JSX, type ReactNode } from "react";
3-
import ToolCard from "./components/tool-card";
4-
import ToolCardLoading from "./components/tool-card-loading";
1+
import type { Tool } from '@/services/apis/gen/queries';
2+
import React, { type JSX, type ReactNode } from 'react';
3+
import ToolCard from './components/tool-card';
4+
import ToolCardLoading from './components/tool-card-loading';
55

66
interface ToolsListProps {
77
data?: Tool[];
@@ -16,32 +16,26 @@ const ToolsList = ({
1616
data,
1717
isLoading,
1818
icon,
19-
title,
20-
emptyMessage = "No tools found",
19+
emptyMessage = 'No tools found',
2120
renderButton,
2221
}: ToolsListProps) => {
2322
return (
2423
<div className="flex flex-col gap-4">
25-
<div className="flex items-center gap-2 text-blue-500">
26-
{icon}
27-
<span className="text font-bold">{title}</span>
28-
</div>
2924
{isLoading ? (
3025
<ToolCardLoading />
3126
) : (
3227
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-4">
3328
{data?.map((tool) => (
34-
<ToolCard
35-
key={tool.id}
36-
tool={tool}
37-
button={renderButton(tool)}
38-
/>
29+
<ToolCard key={tool.id} tool={tool} button={renderButton(tool)} />
3930
))}
4031
</div>
4132
)}
4233
{data?.length === 0 && !isLoading && (
4334
<div className="flex items-center justify-center gap-2 text-blue-500">
44-
{icon && React.cloneElement(icon as JSX.Element, { className: "w-6 h-6 text-gray-500" })}
35+
{icon &&
36+
React.cloneElement(icon as JSX.Element, {
37+
className: 'w-6 h-6 text-gray-500',
38+
})}
4539
<span className="text-gray-500 text-xl font-bold">
4640
{emptyMessage}
4741
</span>
@@ -51,4 +45,4 @@ const ToolsList = ({
5145
);
5246
};
5347

54-
export default ToolsList;
48+
export default ToolsList;

console/src/pages/tools/tools.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
import Page from "@/components/common/page";
2-
import BuiltInTools from "./components/built-in-tools";
3-
import Marketplace from "./components/marketplace";
1+
import Page from '@/components/common/page';
2+
import Marketplace from './components/marketplace';
43

54
const Tools = () => {
65
return (
76
<Page title="Tools">
8-
<BuiltInTools />
97
<Marketplace />
108
</Page>
119
);
1210
};
1311

14-
export default Tools;
12+
export default Tools;

0 commit comments

Comments
 (0)