mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
feat(platform): Updates to agent dashboard (#8598)
* Updates to agent dashboard * fix squished "select all" text in table * fix table alignment --------- Co-authored-by: Swifty <craigswift13@gmail.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { AgentTable } from "./AgentTable";
|
||||
import { AgentTableRowProps } from "./AgentTableRow";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
import { StatusType } from "./Status";
|
||||
|
||||
const meta: Meta<typeof AgentTable> = {
|
||||
title: "AGPT UI/Agent Table",
|
||||
@@ -14,34 +15,37 @@ type Story = StoryObj<typeof AgentTable>;
|
||||
|
||||
const sampleAgents: AgentTableRowProps[] = [
|
||||
{
|
||||
id: "agent-1",
|
||||
agentName: "Super Coder",
|
||||
description: "An AI agent that writes clean, efficient code",
|
||||
imageSrc:
|
||||
"https://ddz4ak4pa3d19.cloudfront.net/cache/53/b2/53b2bc7d7900f0e1e60bf64ebf38032d.jpg",
|
||||
dateSubmitted: "2023-05-15",
|
||||
status: "Active",
|
||||
status: "approved",
|
||||
runs: 1500,
|
||||
rating: 4.8,
|
||||
onEdit: () => console.log("Edit Super Coder"),
|
||||
},
|
||||
{
|
||||
id: "agent-2",
|
||||
agentName: "Data Analyzer",
|
||||
description: "Processes and analyzes large datasets with ease",
|
||||
imageSrc:
|
||||
"https://ddz4ak4pa3d19.cloudfront.net/cache/40/f7/40f7bc97c952f8df0f9c88d29defe8d4.jpg",
|
||||
dateSubmitted: "2023-05-10",
|
||||
status: "Active",
|
||||
status: "awaiting_review",
|
||||
runs: 1200,
|
||||
rating: 4.5,
|
||||
onEdit: () => console.log("Edit Data Analyzer"),
|
||||
},
|
||||
{
|
||||
id: "agent-3",
|
||||
agentName: "UI Designer",
|
||||
description: "Creates beautiful and intuitive user interfaces",
|
||||
imageSrc:
|
||||
"https://ddz4ak4pa3d19.cloudfront.net/cache/14/9e/149ebb9014aa8c0097e72ed89845af0e.jpg",
|
||||
dateSubmitted: "2023-05-05",
|
||||
status: "Inactive",
|
||||
status: "draft",
|
||||
runs: 800,
|
||||
rating: 4.2,
|
||||
onEdit: () => console.log("Edit UI Designer"),
|
||||
|
||||
@@ -9,62 +9,56 @@ export interface AgentTableProps {
|
||||
|
||||
export const AgentTable: React.FC<AgentTableProps> = ({ agents }) => {
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-[1095px]">
|
||||
{/* Table for medium and larger screens */}
|
||||
<div className="hidden md:block">
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
<tr className="border-b border-[#d9d9d9]">
|
||||
<th className="font-['PP Neue Montreal TT'] py-4 text-left text-base leading-[21px] tracking-tight text-[#282828]">
|
||||
Agent
|
||||
</th>
|
||||
<th className="font-['PP Neue Montreal TT'] py-4 text-left text-base leading-[21px] tracking-tight text-[#282828]">
|
||||
Date submitted
|
||||
</th>
|
||||
<th className="font-['PP Neue Montreal TT'] py-4 text-left text-base leading-[21px] tracking-tight text-[#282828]">
|
||||
Status
|
||||
</th>
|
||||
<th className="font-['PP Neue Montreal TT'] py-4 text-left text-base leading-[21px] tracking-tight text-[#282828]">
|
||||
Runs
|
||||
</th>
|
||||
<th className="font-['PP Neue Montreal TT'] py-4 text-left text-base leading-[21px] tracking-tight text-[#282828]">
|
||||
Reviews
|
||||
</th>
|
||||
<th className="font-['PP Neue Montreal TT'] py-4 text-left text-base leading-[21px] tracking-tight text-[#282828]">
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{agents.length > 0 ? (
|
||||
agents.map((agent, index) => (
|
||||
<AgentTableRow key={index} {...agent} />
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td
|
||||
colSpan={6}
|
||||
className="font-['PP Neue Montreal TT'] py-4 text-center text-base text-[#282828]"
|
||||
>
|
||||
No agents available. Create your first agent to get started!
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{/* Cards for small screens */}
|
||||
<div className="block md:hidden">
|
||||
{agents.length > 0 ? (
|
||||
agents.map((agent, index) => (
|
||||
<AgentTableCard key={index} {...agent} />
|
||||
))
|
||||
) : (
|
||||
<div className="font-['PP Neue Montreal TT'] py-4 text-center text-base text-[#707070]">
|
||||
No agents available. Create your first agent to get started!
|
||||
<div className="w-full">
|
||||
{/* Table header - Hide on mobile */}
|
||||
<div className="hidden md:flex flex-col">
|
||||
<div className="border-t border-neutral-300" />
|
||||
<div className="flex items-center px-4 py-2">
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center min-w-[120px]">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="selectAllAgents"
|
||||
aria-label="Select all agents"
|
||||
className="w-5 h-5 rounded border-2 border-neutral-400 mr-4"
|
||||
/>
|
||||
<label
|
||||
htmlFor="selectAllAgents"
|
||||
className="text-sm font-medium text-neutral-800"
|
||||
>
|
||||
Select all
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="grid grid-cols-[400px,150px,150px,100px,100px,50px] w-full items-center ml-2">
|
||||
<div className="text-sm font-medium text-neutral-800">Agent info</div>
|
||||
<div className="text-sm font-medium text-neutral-800">Date submitted</div>
|
||||
<div className="text-sm font-medium text-neutral-800">Status</div>
|
||||
<div className="text-sm font-medium text-neutral-800 text-right">Runs</div>
|
||||
<div className="text-sm font-medium text-neutral-800 text-right">Reviews</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-b border-neutral-300" />
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
{agents.length > 0 ? (
|
||||
<div className="flex flex-col">
|
||||
{agents.map((agent, index) => (
|
||||
<div key={index} className="md:block">
|
||||
<AgentTableRow {...agent} />
|
||||
<div className="block md:hidden">
|
||||
<AgentTableCard {...agent} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="py-4 text-center font-['Geist'] text-base text-neutral-600">
|
||||
No agents available. Create your first agent to get started!
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
// AgentCard.tsx
|
||||
import * as React from "react";
|
||||
import Image from "next/image";
|
||||
import { Button } from "./Button";
|
||||
import { IconStarFilled, IconEdit } from "@/components/ui/icons";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { AgentTableRowProps } from "./AgentTableRow";
|
||||
import { IconStarFilled, IconMore } from "@/components/ui/icons";
|
||||
import { Status, StatusType } from "./Status";
|
||||
|
||||
export const AgentTableCard: React.FC<AgentTableRowProps> = ({
|
||||
export interface AgentTableCardProps {
|
||||
agentName: string;
|
||||
description: string;
|
||||
imageSrc: string;
|
||||
dateSubmitted: string;
|
||||
status: StatusType;
|
||||
runs?: number;
|
||||
rating?: number;
|
||||
onEdit: () => void;
|
||||
}
|
||||
|
||||
export const AgentTableCard: React.FC<AgentTableCardProps> = ({
|
||||
agentName,
|
||||
description,
|
||||
imageSrc,
|
||||
@@ -17,9 +26,9 @@ export const AgentTableCard: React.FC<AgentTableRowProps> = ({
|
||||
onEdit,
|
||||
}) => {
|
||||
return (
|
||||
<Card className="mb-4 p-4">
|
||||
<div className="flex">
|
||||
<div className="relative mr-4 h-20 w-20 overflow-hidden rounded-xl">
|
||||
<div className="p-4 border-b border-neutral-300">
|
||||
<div className="flex gap-4">
|
||||
<div className="relative w-[100px] h-[56px] overflow-hidden rounded-lg bg-[#d9d9d9]">
|
||||
<Image
|
||||
src={imageSrc}
|
||||
alt={agentName}
|
||||
@@ -28,41 +37,33 @@ export const AgentTableCard: React.FC<AgentTableRowProps> = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="mb-2 font-neue text-lg font-medium tracking-tight text-[#272727]">
|
||||
{agentName}
|
||||
</h3>
|
||||
<p className="mb-2 font-neue text-sm leading-tight tracking-tight text-[#282828]">
|
||||
{description}
|
||||
</p>
|
||||
<div className="mb-2 font-neue text-sm leading-tight tracking-tight text-[#282828]">
|
||||
<strong>Date submitted:</strong> {dateSubmitted}
|
||||
</div>
|
||||
<div className="mb-2 font-neue text-sm leading-tight tracking-tight text-[#282828]">
|
||||
<strong>Status:</strong> {status}
|
||||
</div>
|
||||
{runs !== undefined && (
|
||||
<div className="mb-2 font-neue text-sm leading-tight tracking-tight text-[#282828]">
|
||||
<strong>Runs:</strong> {runs.toLocaleString()}
|
||||
</div>
|
||||
)}
|
||||
{rating !== undefined && (
|
||||
<div className="mb-2 flex items-center font-neue text-sm leading-tight tracking-tight text-[#282828]">
|
||||
<strong>Rating:</strong>
|
||||
<span className="ml-2">{rating.toFixed(1)}</span>
|
||||
<IconStarFilled className="ml-1" />
|
||||
</div>
|
||||
)}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="mt-2 flex items-center gap-1"
|
||||
onClick={onEdit}
|
||||
>
|
||||
<IconEdit />
|
||||
<span>Edit</span>
|
||||
</Button>
|
||||
<h3 className="text-[15px] font-medium text-neutral-800">{agentName}</h3>
|
||||
<p className="text-sm text-neutral-600 line-clamp-2">{description}</p>
|
||||
</div>
|
||||
<button onClick={onEdit} className="p-1 hover:bg-neutral-100 rounded-full h-fit">
|
||||
<IconMore className="h-5 w-5 text-neutral-800" />
|
||||
</button>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<div className="mt-4 flex flex-wrap gap-4">
|
||||
<Status status={status} />
|
||||
<div className="text-sm text-neutral-600">
|
||||
{dateSubmitted}
|
||||
</div>
|
||||
{runs && (
|
||||
<div className="text-sm text-neutral-600">
|
||||
{runs.toLocaleString()} runs
|
||||
</div>
|
||||
)}
|
||||
{rating && (
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="text-sm font-medium text-neutral-800">
|
||||
{rating.toFixed(1)}
|
||||
</span>
|
||||
<IconStarFilled className="h-4 w-4 text-neutral-800" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import * as React from "react";
|
||||
import Image from "next/image";
|
||||
import { Button } from "./Button";
|
||||
import { IconStarFilled, IconEdit } from "@/components/ui/icons";
|
||||
import { IconStarFilled, IconEdit, IconMore } from "@/components/ui/icons";
|
||||
import { Status, StatusType } from "./Status";
|
||||
|
||||
export interface AgentTableRowProps {
|
||||
agentName: string;
|
||||
description: string;
|
||||
imageSrc: string;
|
||||
dateSubmitted: string;
|
||||
status: string;
|
||||
status: StatusType;
|
||||
runs?: number;
|
||||
rating?: number;
|
||||
onEdit: () => void;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export const AgentTableRow: React.FC<AgentTableRowProps> = ({
|
||||
@@ -23,57 +25,91 @@ export const AgentTableRow: React.FC<AgentTableRowProps> = ({
|
||||
runs,
|
||||
rating,
|
||||
onEdit,
|
||||
id,
|
||||
}) => {
|
||||
// Create a unique ID for the checkbox
|
||||
const checkboxId = `agent-${id}-checkbox`;
|
||||
|
||||
return (
|
||||
<tr className="border-b border-[#d9d9d9] py-4">
|
||||
<td className="flex items-center">
|
||||
<div className="relative my-4 mr-4 h-20 w-20 overflow-hidden rounded-xl sm:h-20 sm:w-[125px]">
|
||||
<Image
|
||||
src={imageSrc}
|
||||
alt={agentName}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
<div className="hidden md:flex items-center px-4 py-4 border-b border-neutral-300 hover:bg-neutral-50">
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={checkboxId}
|
||||
aria-label={`Select ${agentName}`}
|
||||
className="w-5 h-5 rounded border-2 border-neutral-400 mr-4"
|
||||
/>
|
||||
{/* Single label instead of multiple */}
|
||||
<label
|
||||
htmlFor={checkboxId}
|
||||
className="sr-only"
|
||||
>
|
||||
Select {agentName}
|
||||
</label>
|
||||
</div>
|
||||
<div className="max-w-[293px]">
|
||||
<h3 className="mb-2 font-neue text-lg font-medium tracking-tight text-[#272727]">
|
||||
{agentName}
|
||||
</h3>
|
||||
<p className="font-neue text-sm leading-tight tracking-tight text-[#282828]">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
<td className="font-neue text-base leading-[21px] tracking-tight text-[#282828]">
|
||||
{dateSubmitted}
|
||||
</td>
|
||||
<td className="font-neue text-base leading-[21px] tracking-tight text-[#282828]">
|
||||
{status}
|
||||
</td>
|
||||
<td className="font-neue text-base leading-[21px] tracking-tight text-[#282828]">
|
||||
{runs !== undefined ? runs.toLocaleString() : ""}
|
||||
</td>
|
||||
<td>
|
||||
{rating !== undefined && (
|
||||
<div className="flex items-center">
|
||||
<span className="mr-2 font-neue text-base font-medium tracking-tight text-[#272727]">
|
||||
{rating.toFixed(1)}
|
||||
</span>
|
||||
<IconStarFilled />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-[minmax(400px,1fr),180px,140px,100px,100px,40px] gap-4 w-full items-center">
|
||||
{/* Agent info column */}
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="relative w-[125px] h-[70px] overflow-hidden rounded-[10px] bg-[#d9d9d9]">
|
||||
<Image
|
||||
src={imageSrc}
|
||||
alt={agentName}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex items-center gap-1"
|
||||
onClick={onEdit}
|
||||
>
|
||||
<IconEdit />
|
||||
<span className="font-neue text-sm">Edit</span>
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
<div className="flex flex-col">
|
||||
<h3 className="text-[15px] font-medium text-neutral-800">
|
||||
{agentName}
|
||||
</h3>
|
||||
<p className="text-sm text-neutral-600 line-clamp-2">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Date column */}
|
||||
<div className="text-sm text-neutral-600 pl-14">
|
||||
{dateSubmitted}
|
||||
</div>
|
||||
|
||||
{/* Status column */}
|
||||
<div>
|
||||
<Status status={status} />
|
||||
</div>
|
||||
|
||||
{/* Runs column */}
|
||||
<div className="text-sm text-neutral-600 text-right">
|
||||
{runs?.toLocaleString() ?? '—'}
|
||||
</div>
|
||||
|
||||
{/* Reviews column */}
|
||||
<div className="text-right">
|
||||
{rating ? (
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
<span className="text-sm font-medium text-neutral-800">
|
||||
{rating.toFixed(1)}
|
||||
</span>
|
||||
<IconStarFilled className="h-4 w-4 text-neutral-800" />
|
||||
</div>
|
||||
) : (
|
||||
<span className="text-sm text-neutral-600">—</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Actions - Three dots menu */}
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
onClick={onEdit}
|
||||
className="p-1 hover:bg-neutral-100 rounded-full"
|
||||
>
|
||||
<IconMore className="h-5 w-5 text-neutral-800" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { Status, StatusType } from "./Status";
|
||||
|
||||
const meta = {
|
||||
title: "AGPT UI/Status",
|
||||
component: Status,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
argTypes: {
|
||||
status: {
|
||||
control: 'select',
|
||||
options: ['draft', 'awaiting_review', 'approved', 'rejected'],
|
||||
}
|
||||
}
|
||||
} satisfies Meta<typeof Status>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Draft: Story = {
|
||||
args: {
|
||||
status: "draft" as StatusType,
|
||||
},
|
||||
};
|
||||
|
||||
export const AwaitingReview: Story = {
|
||||
args: {
|
||||
status: "awaiting_review" as StatusType,
|
||||
},
|
||||
};
|
||||
|
||||
export const Approved: Story = {
|
||||
args: {
|
||||
status: "approved" as StatusType,
|
||||
},
|
||||
};
|
||||
|
||||
export const Rejected: Story = {
|
||||
args: {
|
||||
status: "rejected" as StatusType,
|
||||
},
|
||||
};
|
||||
|
||||
export const AllStatuses: Story = {
|
||||
render: () => (
|
||||
<div className="flex flex-col gap-4">
|
||||
<Status status="draft" />
|
||||
<Status status="awaiting_review" />
|
||||
<Status status="approved" />
|
||||
<Status status="rejected" />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
51
autogpt_platform/frontend/src/components/agptui/Status.tsx
Normal file
51
autogpt_platform/frontend/src/components/agptui/Status.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import * as React from "react";
|
||||
|
||||
export type StatusType = "draft" | "awaiting_review" | "approved" | "rejected";
|
||||
|
||||
interface StatusProps {
|
||||
status: StatusType;
|
||||
}
|
||||
|
||||
const statusConfig: Record<StatusType, {
|
||||
bgColor: string;
|
||||
dotColor: string;
|
||||
text: string;
|
||||
}> = {
|
||||
draft: {
|
||||
bgColor: "bg-blue-50",
|
||||
dotColor: "bg-blue-500",
|
||||
text: "Draft"
|
||||
},
|
||||
awaiting_review: {
|
||||
bgColor: "bg-amber-50",
|
||||
dotColor: "bg-amber-500",
|
||||
text: "Awaiting review"
|
||||
},
|
||||
approved: {
|
||||
bgColor: "bg-green-50",
|
||||
dotColor: "bg-green-500",
|
||||
text: "Approved"
|
||||
},
|
||||
rejected: {
|
||||
bgColor: "bg-red-50",
|
||||
dotColor: "bg-red-500",
|
||||
text: "Rejected"
|
||||
}
|
||||
};
|
||||
|
||||
export const Status: React.FC<StatusProps> = ({ status }) => {
|
||||
if (!status || !statusConfig[status]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const config = statusConfig[status];
|
||||
|
||||
return (
|
||||
<div className={`px-2.5 py-1 ${config.bgColor} rounded-[26px] flex items-center gap-1.5`}>
|
||||
<div className={`w-3 h-3 ${config.dotColor} rounded-full`} />
|
||||
<div className="text-neutral-600 text-sm font-normal font-['Geist'] leading-tight">
|
||||
{config.text}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { CreatorDashboardPage } from "./CreatorDashboardPage";
|
||||
import { IconType } from "../../ui/icons";
|
||||
import { StatusType } from "../Status";
|
||||
|
||||
const meta: Meta<typeof CreatorDashboardPage> = {
|
||||
title: "AGPT UI/Agent Store/Creator Dashboard Page",
|
||||
@@ -80,7 +81,7 @@ const sampleAgents = [
|
||||
imageSrc:
|
||||
"https://ddz4ak4pa3d19.cloudfront.net/cache/11/47/114784105a9b180e08e117cbf2612e5b.jpg",
|
||||
dateSubmitted: "2023-05-15",
|
||||
status: "Active",
|
||||
status: "approved" as StatusType,
|
||||
runs: 1500,
|
||||
rating: 4.8,
|
||||
onEdit: () => console.log("Edit Super Coder"),
|
||||
@@ -91,11 +92,22 @@ const sampleAgents = [
|
||||
imageSrc:
|
||||
"https://ddz4ak4pa3d19.cloudfront.net/cache/40/f7/40f7bc97c952f8df0f9c88d29defe8d4.jpg",
|
||||
dateSubmitted: "2023-05-10",
|
||||
status: "Active",
|
||||
status: "awaiting_review" as StatusType,
|
||||
runs: 1200,
|
||||
rating: 4.5,
|
||||
onEdit: () => console.log("Edit Data Analyzer"),
|
||||
},
|
||||
{
|
||||
agentName: "UI Designer",
|
||||
description: "Creates beautiful and intuitive user interfaces",
|
||||
imageSrc:
|
||||
"https://ddz4ak4pa3d19.cloudfront.net/cache/14/9e/149ebb9014aa8c0097e72ed89845af0e.jpg",
|
||||
dateSubmitted: "2023-05-05",
|
||||
status: "draft" as StatusType,
|
||||
runs: 800,
|
||||
rating: 4.2,
|
||||
onEdit: () => console.log("Edit UI Designer"),
|
||||
},
|
||||
];
|
||||
|
||||
export const Default: Story = {
|
||||
@@ -126,6 +138,9 @@ export const ManyAgents: Story = {
|
||||
.map((agent, index) => ({
|
||||
...agent,
|
||||
agentName: `Agent ${index + 1}`,
|
||||
status: ["approved", "awaiting_review", "draft", "rejected"][index % 4] as StatusType,
|
||||
rating: Math.round((4 + Math.random()) * 10) / 10,
|
||||
runs: Math.floor(Math.random() * 2000) + 500,
|
||||
onEdit: () => console.log(`Edit Agent ${index + 1}`),
|
||||
})),
|
||||
},
|
||||
|
||||
@@ -60,35 +60,43 @@ export const CreatorDashboardPage: React.FC<CreatorDashboardPageProps> = ({
|
||||
menuItemGroups={menuItemGroups}
|
||||
/>
|
||||
|
||||
<div className="flex">
|
||||
<div className="flex flex-col md:flex-row">
|
||||
<Sidebar linkGroups={sidebarLinkGroups} />
|
||||
|
||||
<main className="flex-1 px-6 py-8 md:px-10">
|
||||
<main className="flex-1 px-4 py-6 md:px-10 md:py-8">
|
||||
{/* Header Section */}
|
||||
<div className="mb-8 flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
||||
<div>
|
||||
<h1 className="font-neue text-3xl font-medium leading-9 tracking-tight text-neutral-900">
|
||||
Submit a New Agent
|
||||
</h1>
|
||||
<p className="mt-2 font-neue text-sm text-[#707070]">
|
||||
Select from the list of agents you currently have, or upload
|
||||
from your local machine.
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="default" size="lg">
|
||||
Create New Agent
|
||||
</Button>
|
||||
<div className="mb-6 md:mb-8">
|
||||
<h1 className="text-2xl md:text-[32px] font-medium leading-tight md:leading-[38px] text-neutral-900">
|
||||
Agent dashboard
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<Separator className="mb-8" />
|
||||
|
||||
{/* Agents Section */}
|
||||
<div>
|
||||
<h2 className="mb-4 text-xl font-bold text-neutral-900">
|
||||
Your Agents
|
||||
{/* Submit Agent Section */}
|
||||
<div className="mb-6 md:mb-8">
|
||||
<h2 className="mb-1 text-lg md:text-[20px] font-medium leading-tight md:leading-[24px] text-neutral-900">
|
||||
Submit an agent
|
||||
</h2>
|
||||
<AgentTable agents={agents} />
|
||||
<div className="flex flex-col md:flex-row md:justify-between md:items-end gap-4 md:gap-0">
|
||||
<p className="text-sm md:text-[14px] leading-[20px] text-neutral-600">
|
||||
Select from the list of agents you currently already have, or upload from your local machine.
|
||||
</p>
|
||||
<button className="w-full md:w-auto h-12 px-5 py-3 bg-neutral-800 rounded-[38px] inline-flex items-center justify-center md:justify-start gap-2.5 md:ml-4">
|
||||
<span className="text-white text-base font-medium font-['Geist'] leading-normal">Submit agent</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator className="my-6 md:my-8 bg-neutral-300" />
|
||||
|
||||
{/* Agents List Section */}
|
||||
<div className="mb-4 md:mb-6">
|
||||
<h2 className="text-lg md:text-[20px] font-medium leading-tight md:leading-[24px] text-neutral-900">
|
||||
Your uploaded agents
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Agent Table */}
|
||||
<AgentTable agents={agents} />
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1504,6 +1504,41 @@ export const IconSliders = createIcon((props) => (
|
||||
</svg>
|
||||
));
|
||||
|
||||
/**
|
||||
* More (vertical dots) icon component.
|
||||
*
|
||||
* @component IconMore
|
||||
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
|
||||
* @returns {JSX.Element} - The more options icon.
|
||||
*
|
||||
* @example
|
||||
* // Default usage
|
||||
* <IconMore />
|
||||
*
|
||||
* @example
|
||||
* // With custom color and size
|
||||
* <IconMore className="text-neutral-800" size="lg" />
|
||||
*/
|
||||
export const IconMore = createIcon((props) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
aria-label="More Icon"
|
||||
{...props}
|
||||
>
|
||||
<path d="M10 10.8333C10.4603 10.8333 10.8334 10.4602 10.8334 9.99999C10.8334 9.53975 10.4603 9.16666 10 9.16666C9.53978 9.16666 9.16669 9.53975 9.16669 9.99999C9.16669 10.4602 9.53978 10.8333 10 10.8333Z" />
|
||||
<path d="M10 4.99999C10.4603 4.99999 10.8334 4.6269 10.8334 4.16666C10.8334 3.70642 10.4603 3.33333 10 3.33333C9.53978 3.33333 9.16669 3.70642 9.16669 4.16666C9.16669 4.6269 9.53978 4.99999 10 4.99999Z" />
|
||||
<path d="M10 16.6667C10.4603 16.6667 10.8334 16.2936 10.8334 15.8333C10.8334 15.3731 10.4603 15 10 15C9.53978 15 9.16669 15.3731 9.16669 15.8333C9.16669 16.2936 9.53978 16.6667 10 16.6667Z" />
|
||||
</svg>
|
||||
));
|
||||
|
||||
/**
|
||||
* External link icon component.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user