Added deleting submissions and viewing the popout

This commit is contained in:
SwiftyOS
2024-12-02 16:54:56 +01:00
parent 48d27c91d4
commit fdb82eda38
19 changed files with 381 additions and 77 deletions

View File

@@ -275,7 +275,10 @@ async def get_store_submissions(
# Convert to response models
submission_models = [
backend.server.v2.store.model.StoreSubmission(
agent_id=sub.agent_id,
agent_version=sub.agent_version,
name=sub.name,
sub_heading=sub.sub_heading,
slug=sub.slug,
description=sub.description,
image_urls=sub.image_urls or [],
@@ -312,6 +315,49 @@ async def get_store_submissions(
)
async def delete_store_submission(
user_id: str,
submission_id: str,
) -> bool:
"""
Delete a store listing submission.
Args:
user_id: ID of the authenticated user
submission_id: ID of the submission to be deleted
Returns:
bool: True if the submission was successfully deleted, False otherwise
"""
logger.debug(f"Deleting store submission {submission_id} for user {user_id}")
try:
# Verify the submission belongs to this user
submission = await prisma.models.StoreListing.prisma().find_first(
where={"agentId": submission_id, "owningUserId": user_id}
)
if not submission:
logger.warning(f"Submission not found for user {user_id}: {submission_id}")
raise backend.server.v2.store.exceptions.SubmissionNotFoundError(
f"Submission not found for this user. User ID: {user_id}, Submission ID: {submission_id}"
)
# Delete the submission
await prisma.models.StoreListing.prisma().delete(
where=prisma.types.StoreListingWhereUniqueInput(id=submission.id)
)
logger.debug(
f"Successfully deleted submission {submission_id} for user {user_id}"
)
return True
except Exception as e:
logger.error(f"Error deleting store submission: {str(e)}")
return False
async def create_store_submission(
user_id: str,
agent_id: str,
@@ -398,8 +444,11 @@ async def create_store_submission(
logger.debug(f"Created store listing for agent {agent_id}")
# Return submission details
return backend.server.v2.store.model.StoreSubmission(
agent_id=agent_id,
agent_version=agent_version,
name=name,
slug=slug,
sub_heading=sub_heading,
description=description,
image_urls=image_urls,
date_submitted=listing.createdAt,

View File

@@ -68,3 +68,9 @@ class ProfileNotFoundError(StoreError):
"""Raised when a profile is not found"""
pass
class SubmissionNotFoundError(StoreError):
"""Raised when a submission is not found"""
pass

View File

@@ -100,7 +100,10 @@ class Profile(pydantic.BaseModel):
class StoreSubmission(pydantic.BaseModel):
agent_id: str
agent_version: int
name: str
sub_heading: str
slug: str
description: str
image_urls: list[str]

View File

@@ -243,6 +243,38 @@ async def get_my_agents(
raise
@router.delete(
"/submissions/{submission_id}",
tags=["store", "private"],
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
)
async def delete_submission(
user_id: typing.Annotated[
str, fastapi.Depends(autogpt_libs.auth.depends.get_user_id)
],
submission_id: str,
) -> bool:
"""
Delete a store listing submission.
Args:
user_id (str): ID of the authenticated user
submission_id (str): ID of the submission to be deleted
Returns:
bool: True if the submission was successfully deleted, False otherwise
"""
try:
result = await backend.server.v2.store.db.delete_store_submission(
user_id=user_id,
submission_id=submission_id,
)
return result
except Exception:
logger.exception("Exception occurred whilst deleting store submission")
raise
@router.get(
"/submissions",
tags=["store", "private"],

View File

@@ -91,8 +91,11 @@ CREATE VIEW "StoreSubmission" AS
SELECT
sl.id as listing_id,
sl."owningUserId" as user_id,
slv."agentId" as agent_id,
slv."version" as agent_version,
slv.slug,
slv.name,
slv."subHeading" as sub_heading,
slv.description,
slv."imageUrls" as image_urls,
slv."createdAt" as date_submitted,
@@ -107,9 +110,9 @@ LEFT JOIN (
SELECT "agentGraphId", COUNT(*) as run_count
FROM "AgentGraphExecution"
GROUP BY "agentGraphId"
) ar ON ar."agentGraphId" = sl."agentId"
) ar ON ar."agentGraphId" = slv."agentId"
WHERE sl."isDeleted" = FALSE
GROUP BY sl.id, sl."owningUserId", slv."createdAt", slv.slug, slv.name, slv.description, slv."imageUrls",
sls."createdAt", sls."Status", ar.run_count;
GROUP BY sl.id, sl."owningUserId", slv."agentId", slv."version", slv.slug, slv.name, slv."subHeading",
slv.description, slv."imageUrls", slv."createdAt", sls."Status", ar.run_count;
COMMIT;

View File

@@ -479,12 +479,15 @@ view StoreSubmission {
user_id String
slug String
name String
sub_heading String
description String
image_urls String[]
date_submitted DateTime
status SubmissionStatus
runs Int
rating Float
agent_id String
agent_version Int
@@index([user_id])
}

View File

@@ -1,15 +1,26 @@
"use client";
import * as React from "react";
import { AgentTable } from "@/components/agptui/AgentTable";
import { AgentTableRowProps } from "@/components/agptui/AgentTableRow";
import { Button } from "@/components/agptui/Button";
import { Separator } from "@/components/ui/separator";
import AutoGPTServerAPIServerSide from "@/lib/autogpt-server-api";
import { createServerClient } from "@/lib/supabase/server";
import AutoGPTServerAPI from "@/lib/autogpt-server-api";
import { createClient } from "@/lib/supabase/client";
import { StatusType } from "@/components/agptui/Status";
import { PublishAgentPopout } from "@/components/agptui/composite/PublishAgentPopout";
import { useCallback, useEffect, useState } from "react";
import {
StoreSubmissionsResponse,
StoreSubmissionRequest,
} from "@/lib/autogpt-server-api/types";
async function getDashboardData() {
// Get the supabase client first
const supabase = createServerClient();
const supabase = createClient();
if (!supabase) {
return { submissions: [] };
}
const {
data: { session },
} = await supabase.auth.getSession();
@@ -19,11 +30,10 @@ async function getDashboardData() {
return { profile: null };
}
// Create API client with the same supabase instance
const api = new AutoGPTServerAPIServerSide(
const api = new AutoGPTServerAPI(
process.env.NEXT_PUBLIC_AGPT_SERVER_URL,
process.env.NEXT_PUBLIC_AGPT_WS_SERVER_URL,
supabase, // Pass the supabase client instance
supabase,
);
try {
@@ -39,12 +49,57 @@ async function getDashboardData() {
}
}
export default async function Page({
export default function Page({
params: { lang },
}: {
params: { lang: string };
}) {
const { submissions } = await getDashboardData();
const [submissions, setSubmissions] = useState<StoreSubmissionsResponse>();
const [openPopout, setOpenPopout] = useState<boolean>(false);
const [submissionData, setSubmissionData] =
useState<StoreSubmissionRequest>();
const [popoutStep, setPopoutStep] = useState<"select" | "info" | "review">(
"info",
);
const fetchData = useCallback(async () => {
const { submissions } = await getDashboardData();
if (submissions) {
setSubmissions(submissions as StoreSubmissionsResponse);
}
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);
const onEditSubmission = useCallback((submission: StoreSubmissionRequest) => {
setSubmissionData(submission);
setPopoutStep("review");
setOpenPopout(true);
}, []);
const onDeleteSubmission = useCallback(
(submission_id: string) => {
const supabase = createClient();
if (!supabase) {
return;
}
const api = new AutoGPTServerAPI(
process.env.NEXT_PUBLIC_AGPT_SERVER_URL,
process.env.NEXT_PUBLIC_AGPT_WS_SERVER_URL,
supabase,
);
api.deleteStoreSubmission(submission_id);
fetchData();
},
[fetchData],
);
const onOpenPopout = useCallback(() => {
setPopoutStep("select");
setOpenPopout(true);
}, []);
return (
<main className="flex-1 px-6 py-8 md:px-10">
@@ -61,10 +116,13 @@ export default async function Page({
</div>
<PublishAgentPopout
trigger={
<Button variant="default" size="lg">
<Button variant="default" size="lg" onClick={onOpenPopout}>
Create New Agent
</Button>
}
openPopout={openPopout}
inputStep={popoutStep}
submissionData={submissionData}
/>
</div>
@@ -77,17 +135,25 @@ export default async function Page({
</h2>
<AgentTable
agents={
submissions?.submissions.map((submission, index) => ({
(submissions?.submissions.map((submission, index) => ({
id: index,
agent_id: submission.agent_id,
agent_version: submission.agent_version,
sub_heading: submission.sub_heading,
date_submitted: submission.date_submitted,
agentName: submission.name,
description: submission.description,
imageSrc: submission.image_urls[0] || "",
imageSrc: submission.image_urls || [""],
dateSubmitted: new Date(
submission.date_submitted,
).toLocaleDateString(),
status: submission.status.toLowerCase() as StatusType,
})) || []
runs: submission.runs,
rating: submission.rating,
})) as AgentTableRowProps[]) || []
}
onEditSubmission={onEditSubmission}
onDeleteSubmission={onDeleteSubmission}
/>
</div>
</main>

View File

@@ -87,7 +87,7 @@ function SearchResults({
if (sortValue === "runs") {
sortBy = "runs";
} else if (sortValue === "rating") {
sortBy = "rating";
sortBy = "rating";
}
const sortedAgents = [...agents].sort((a, b) => {
@@ -96,7 +96,9 @@ function SearchResults({
} else if (sortBy === "rating") {
return b.rating - a.rating;
} else {
return new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime();
return (
new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
);
}
});

View File

@@ -3,12 +3,36 @@
import * as React from "react";
import { AgentTableRow, AgentTableRowProps } from "./AgentTableRow";
import { AgentTableCard } from "./AgentTableCard";
import { StoreSubmissionRequest } from "@/lib/autogpt-server-api/types";
export interface AgentTableProps {
agents: AgentTableRowProps[];
onEditSubmission: (submission: StoreSubmissionRequest) => void;
onDeleteSubmission: (submission_id: string) => void;
}
export const AgentTable: React.FC<AgentTableProps> = ({ agents }) => {
export const AgentTable: React.FC<AgentTableProps> = ({
agents,
onEditSubmission,
onDeleteSubmission,
}) => {
// Use state to track selected agents
const [selectedAgents, setSelectedAgents] = React.useState<Set<string>>(
new Set(),
);
// Handle select all checkbox
const handleSelectAll = React.useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.checked) {
setSelectedAgents(new Set(agents.map((agent) => agent.id.toString())));
} else {
setSelectedAgents(new Set());
}
},
[agents],
);
return (
<div className="w-full">
{/* Table header - Hide on mobile */}
@@ -22,6 +46,10 @@ export const AgentTable: React.FC<AgentTableProps> = ({ agents }) => {
id="selectAllAgents"
aria-label="Select all agents"
className="mr-4 h-5 w-5 rounded border-2 border-neutral-400 dark:border-neutral-600"
checked={
selectedAgents.size === agents.length && agents.length > 0
}
onChange={handleSelectAll}
/>
<label
htmlFor="selectAllAgents"
@@ -57,8 +85,12 @@ export const AgentTable: React.FC<AgentTableProps> = ({ agents }) => {
{agents.length > 0 ? (
<div className="flex flex-col">
{agents.map((agent, index) => (
<div key={index} className="md:block">
<AgentTableRow {...agent} />
<div key={agent.id} className="md:block">
<AgentTableRow
{...agent}
onEditSubmission={onEditSubmission}
onDeleteSubmission={onDeleteSubmission}
/>
<div className="block md:hidden">
<AgentTableCard {...agent} />
</div>

View File

@@ -6,26 +6,46 @@ import { IconStarFilled, IconMore } from "@/components/ui/icons";
import { Status, StatusType } from "./Status";
export interface AgentTableCardProps {
agent_id: string;
agent_version: number;
agentName: string;
sub_heading: string;
description: string;
imageSrc: string;
imageSrc: string[];
dateSubmitted: string;
status: StatusType;
runs?: number;
rating?: number;
runs: number;
rating: number;
id: number;
onEditSubmission: (submission: StoreSubmissionRequest) => void;
}
export const AgentTableCard: React.FC<AgentTableCardProps> = ({
agent_id,
agent_version,
agentName,
sub_heading,
description,
imageSrc,
dateSubmitted,
status,
runs,
rating,
id,
onEditSubmission,
}) => {
const onEdit = () => {
console.log("Edit agent", agentName);
onEditSubmission({
agent_id,
agent_version,
slug: "",
name: agentName,
sub_heading,
description,
image_urls: imageSrc,
categories: [],
});
};
return (
@@ -33,7 +53,7 @@ export const AgentTableCard: React.FC<AgentTableCardProps> = ({
<div className="flex gap-4">
<div className="relative h-[56px] w-[100px] overflow-hidden rounded-lg bg-[#d9d9d9] dark:bg-neutral-800">
<Image
src={imageSrc}
src={imageSrc?.[0] ?? "/nada.png"}
alt={agentName}
fill
style={{ objectFit: "cover" }}
@@ -60,19 +80,15 @@ export const AgentTableCard: React.FC<AgentTableCardProps> = ({
<div className="text-sm text-neutral-600 dark:text-neutral-400">
{dateSubmitted}
</div>
{runs && (
<div className="text-sm text-neutral-600 dark:text-neutral-400">
{runs.toLocaleString()} runs
</div>
)}
{rating && (
<div className="flex items-center gap-1">
<span className="text-sm font-medium text-neutral-800 dark:text-neutral-200">
{rating.toFixed(1)}
</span>
<IconStarFilled className="h-4 w-4 text-neutral-800 dark:text-neutral-200" />
</div>
)}
<div className="text-sm text-neutral-600 dark:text-neutral-400">
{runs.toLocaleString()} runs
</div>
<div className="flex items-center gap-1">
<span className="text-sm font-medium text-neutral-800 dark:text-neutral-200">
{rating.toFixed(1)}
</span>
<IconStarFilled className="h-4 w-4 text-neutral-800 dark:text-neutral-200" />
</div>
</div>
</div>
);

View File

@@ -2,23 +2,34 @@
import * as React from "react";
import Image from "next/image";
import { Button } from "./Button";
import { IconStarFilled, IconEdit, IconMore } from "@/components/ui/icons";
import { IconStarFilled, IconMore, IconEdit } from "@/components/ui/icons";
import { Status, StatusType } from "./Status";
import * as ContextMenu from "@radix-ui/react-context-menu";
import { TrashIcon } from "@radix-ui/react-icons";
import { StoreSubmissionRequest } from "@/lib/autogpt-server-api/types";
export interface AgentTableRowProps {
agent_id: string;
agent_version: number;
agentName: string;
sub_heading: string;
description: string;
imageSrc: string;
dateSubmitted: string;
imageSrc: string[];
date_submitted: string;
status: StatusType;
runs?: number;
rating?: number;
runs: number;
rating: number;
dateSubmitted: string;
id: number;
onEditSubmission: (submission: StoreSubmissionRequest) => void;
onDeleteSubmission: (submission_id: string) => void;
}
export const AgentTableRow: React.FC<AgentTableRowProps> = ({
agent_id,
agent_version,
agentName,
sub_heading,
description,
imageSrc,
dateSubmitted,
@@ -26,13 +37,36 @@ export const AgentTableRow: React.FC<AgentTableRowProps> = ({
runs,
rating,
id,
onEditSubmission,
onDeleteSubmission,
}) => {
// Create a unique ID for the checkbox
const checkboxId = `agent-${id}-checkbox`;
const onEdit = () => {
console.log("Edit agent", id);
};
const handleEdit = React.useCallback(() => {
onEditSubmission({
agent_id,
agent_version,
slug: "",
name: agentName,
sub_heading,
description,
image_urls: imageSrc,
categories: [],
} as StoreSubmissionRequest);
}, [
agent_id,
agent_version,
agentName,
sub_heading,
description,
imageSrc,
onEditSubmission,
]);
const handleDelete = React.useCallback(() => {
onDeleteSubmission(agent_id);
}, [agent_id, onDeleteSubmission]);
return (
<div className="hidden items-center border-b border-neutral-300 px-4 py-4 hover:bg-neutral-50 dark:border-neutral-700 dark:hover:bg-neutral-800 md:flex">
@@ -56,7 +90,7 @@ export const AgentTableRow: React.FC<AgentTableRowProps> = ({
<div className="flex items-center gap-4">
<div className="relative h-[70px] w-[125px] overflow-hidden rounded-[10px] bg-[#d9d9d9] dark:bg-neutral-700">
<Image
src={imageSrc}
src={imageSrc?.[0] ?? "/nada.png"}
alt={agentName}
fill
style={{ objectFit: "cover" }}
@@ -105,12 +139,30 @@ export const AgentTableRow: React.FC<AgentTableRowProps> = ({
{/* Actions - Three dots menu */}
<div className="flex justify-end">
<button
onClick={onEdit}
className="rounded-full p-1 hover:bg-neutral-100 dark:hover:bg-neutral-700"
>
<IconMore className="h-5 w-5 text-neutral-800 dark:text-neutral-200" />
</button>
<ContextMenu.Root>
<ContextMenu.Trigger>
<button className="rounded-full p-1 hover:bg-neutral-100 dark:hover:bg-neutral-700">
<IconMore className="h-5 w-5 text-neutral-800 dark:text-neutral-200" />
</button>
</ContextMenu.Trigger>
<ContextMenu.Content className="z-10 rounded-xl border bg-white p-1 shadow-md dark:bg-gray-800">
<ContextMenu.Item
onSelect={handleEdit}
className="flex cursor-pointer items-center rounded-md px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700"
>
<IconEdit className="mr-2 h-5 w-5 dark:text-gray-100" />
<span className="dark:text-gray-100">Edit</span>
</ContextMenu.Item>
<ContextMenu.Separator className="my-1 h-px bg-gray-300 dark:bg-gray-600" />
<ContextMenu.Item
onSelect={handleDelete}
className="flex cursor-pointer items-center rounded-md px-3 py-2 text-red-500 hover:bg-gray-100 dark:hover:bg-gray-700"
>
<TrashIcon className="mr-2 h-5 w-5 text-red-500 dark:text-red-400" />
<span className="dark:text-red-400">Delete</span>
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Root>
</div>
</div>
</div>

View File

@@ -26,12 +26,12 @@ export const BecomeACreator: React.FC<BecomeACreatorProps> = ({
<div className="left-0 top-0 h-px w-full bg-gray-200 dark:bg-gray-700" />
{/* Title */}
<div className="pt-4 mb-4 left-4 top-[26px] font-['Poppins'] text-base font-semibold leading-7 text-neutral-800 dark:text-neutral-200 md:left-6 md:text-lg lg:left-8">
<div className="left-4 top-[26px] mb-4 pt-4 font-['Poppins'] text-base font-semibold leading-7 text-neutral-800 dark:text-neutral-200 md:left-6 md:text-lg lg:left-8">
{title}
</div>
{/* Content Container */}
<div className="absolute left-1/2 top-1/2 w-full max-w-[900px] -translate-x-1/2 -translate-y-1/2 px-4 pt-16 md:pt-10 text-center md:px-6 lg:px-0">
<div className="absolute left-1/2 top-1/2 w-full max-w-[900px] -translate-x-1/2 -translate-y-1/2 px-4 pt-16 text-center md:px-6 md:pt-10 lg:px-0">
<h2 className="font-poppins mb-6 text-3xl font-semibold leading-tight text-neutral-950 dark:text-neutral-50 md:mb-8 md:text-4xl md:leading-[1.2] lg:mb-12 lg:text-5xl lg:leading-[54px]">
Build AI agents and share
<br />

View File

@@ -14,7 +14,6 @@ import { CreatorDetails, ProfileDetails } from "@/lib/autogpt-server-api/types";
import { createClient } from "@/lib/supabase/client";
import { Separator } from "@/components/ui/separator";
export const ProfileInfoForm = ({ profile }: { profile: CreatorDetails }) => {
const [isSubmitting, setIsSubmitting] = useState(false);
const [profileData, setProfileData] = useState(profile);
@@ -252,7 +251,7 @@ export const ProfileInfoForm = ({ profile }: { profile: CreatorDetails }) => {
<Separator />
<div className="py-8 flex h-[50px] items-center justify-end gap-3">
<div className="flex h-[50px] items-center justify-end gap-3 py-8">
<Button
type="button"
variant="secondary"

View File

@@ -149,6 +149,9 @@ export const ProfilePopoutMenu: React.FC<ProfilePopoutMenuProps> = ({
</div>
</div>
}
inputStep="select"
submissionData={null}
openPopout={false}
/>
);
} else {

View File

@@ -102,7 +102,9 @@ export const SettingsInputForm = ({
/>
</div>
{!passwordsMatch && (
<p className="text-red-500 text-sm mt-1">Passwords do not match</p>
<p className="mt-1 text-sm text-red-500">
Passwords do not match
</p>
)}
</div>
</div>

View File

@@ -20,17 +20,16 @@ import AutoGPTServerAPI from "@/lib/autogpt-server-api/client";
import { useRouter } from "next/navigation";
interface PublishAgentPopoutProps {
trigger?: React.ReactNode;
openPopout?: boolean;
inputStep?: "select" | "info" | "review";
submissionData?: StoreSubmissionRequest;
}
export const PublishAgentPopout: React.FC<PublishAgentPopoutProps> = ({
trigger,
}) => {
const [step, setStep] = React.useState<"select" | "info" | "review">(
"select",
);
const [myAgents, setMyAgents] = React.useState<MyAgentsResponse | null>(null);
const [selectedAgent, setSelectedAgent] = React.useState<string | null>(null);
const [publishData, setPublishData] = React.useState<StoreSubmissionRequest>({
openPopout = false,
inputStep = "select",
submissionData = {
name: "",
sub_heading: "",
slug: "",
@@ -39,7 +38,15 @@ export const PublishAgentPopout: React.FC<PublishAgentPopoutProps> = ({
agent_id: "",
agent_version: 0,
categories: [],
});
},
}) => {
const [step, setStep] = React.useState<"select" | "info" | "review">(
inputStep,
);
const [myAgents, setMyAgents] = React.useState<MyAgentsResponse | null>(null);
const [selectedAgent, setSelectedAgent] = React.useState<string | null>(null);
const [publishData, setPublishData] =
React.useState<StoreSubmissionRequest>(submissionData);
const [selectedAgentId, setSelectedAgentId] = React.useState<string | null>(
null,
);
@@ -51,15 +58,27 @@ export const PublishAgentPopout: React.FC<PublishAgentPopoutProps> = ({
const popupId = React.useId();
const router = useRouter();
const supabase = createClient();
const supabase = React.useMemo(() => createClient(), []);
const api = new AutoGPTServerAPI(
process.env.NEXT_PUBLIC_AGPT_SERVER_URL,
process.env.NEXT_PUBLIC_AGPT_WS_SERVER_URL,
supabase,
const api = React.useMemo(
() =>
new AutoGPTServerAPI(
process.env.NEXT_PUBLIC_AGPT_SERVER_URL,
process.env.NEXT_PUBLIC_AGPT_WS_SERVER_URL,
supabase,
),
[supabase],
);
React.useEffect(() => {
console.log("PublishAgentPopout Effect");
setOpen(openPopout);
setStep(inputStep);
setPublishData(submissionData);
}, [openPopout]);
React.useEffect(() => {
console.log("LoadMyAgents Effect");
if (open) {
const loadMyAgents = async () => {
try {
@@ -213,7 +232,10 @@ export const PublishAgentPopout: React.FC<PublishAgentPopoutProps> = ({
thumbnailSrc={publishData.image_urls[0]}
onClose={handleClose}
onDone={handleClose}
onViewProgress={() => router.push("/store/dashboard")}
onViewProgress={() => {
router.push("/store/dashboard");
handleClose();
}}
/>
</div>
</div>
@@ -223,7 +245,14 @@ export const PublishAgentPopout: React.FC<PublishAgentPopoutProps> = ({
};
return (
<Popover open={open} onOpenChange={setOpen}>
<Popover
open={open}
onOpenChange={(isOpen) => {
if (isOpen !== open) {
setOpen(isOpen);
}
}}
>
<PopoverTrigger asChild>
{trigger || <Button variant="default">Publish Agent</Button>}
</PopoverTrigger>

View File

@@ -1,9 +1,9 @@
/* flow.css or index.css */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", sans-serif;
}
code {

View File

@@ -323,6 +323,10 @@ export default class BaseAutoGPTServerAPI {
return this._request("POST", "/store/submissions", submission);
}
deleteStoreSubmission(submission_id: string): Promise<boolean> {
return this._request("DELETE", `/store/submissions/${submission_id}`);
}
uploadStoreSubmissionMedia(file: File): Promise<string> {
const formData = new FormData();
formData.append("file", file);

View File

@@ -417,7 +417,10 @@ export type CreatorDetails = {
};
export type StoreSubmission = {
agent_id: string;
agent_version: number;
name: string;
sub_heading: string;
description: string;
image_urls: string[];
date_submitted: string;