diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/NewAgentLibraryView.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/NewAgentLibraryView.tsx index b06901f860..f951c09522 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/NewAgentLibraryView.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/NewAgentLibraryView.tsx @@ -72,7 +72,7 @@ export function NewAgentLibraryView() { } return ( -
+
0 || Object.keys(agentCredentialsInputFields || {}).length > 0; + const isTriggerRunType = defaultRunType.includes("trigger"); + function handleInputChange(key: string, value: string) { setInputValues((prev) => ({ ...prev, @@ -153,7 +155,7 @@ export function RunAgentModal({
- {!allRequiredInputsAreSet ? ( + {isTriggerRunType ? null : !allRequiredInputsAreSet ? ( diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/other/EmptyTasks.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/other/EmptyTasks.tsx index c0c2c900a1..62a75e4993 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/other/EmptyTasks.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/other/EmptyTasks.tsx @@ -1,8 +1,14 @@ +"use client"; + +import { getV1GetGraphVersion } from "@/app/api/__generated__/endpoints/graphs/graphs"; import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { Button } from "@/components/atoms/Button/Button"; import { Text } from "@/components/atoms/Text/Text"; import { ShowMoreText } from "@/components/molecules/ShowMoreText/ShowMoreText"; +import { useToast } from "@/components/molecules/Toast/use-toast"; +import { exportAsJSONFile } from "@/lib/utils"; import { formatDate } from "@/lib/utils/time"; +import Link from "next/link"; import { RunAgentModal } from "../modals/RunAgentModal/RunAgentModal"; import { RunDetailCard } from "../selected-views/RunDetailCard/RunDetailCard"; import { EmptyTasksIllustration } from "./EmptyTasksIllustration"; @@ -12,6 +18,30 @@ type Props = { }; export function EmptyTasks({ agent }: Props) { + const { toast } = useToast(); + + async function handleExport() { + try { + const res = await getV1GetGraphVersion( + agent.graph_id, + agent.graph_version, + { for_export: true }, + ); + if (res.status === 200) { + const filename = `${agent.name}_v${agent.graph_version}.json`; + exportAsJSONFile(res.data as any, filename); + toast({ title: "Agent exported" }); + } else { + toast({ title: "Failed to export agent", variant: "destructive" }); + } + } catch (e: any) { + toast({ + title: "Failed to export agent", + description: e?.message, + variant: "destructive", + }); + } + } const isPublished = Boolean(agent.marketplace_listing); const createdAt = formatDate(agent.created_at); const updatedAt = formatDate(agent.updated_at); @@ -93,10 +123,15 @@ export function EmptyTasks({ agent }: Props) { ) : null}
- -
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/AnchorLinksWrap.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/AnchorLinksWrap.tsx new file mode 100644 index 0000000000..6dae969142 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/AnchorLinksWrap.tsx @@ -0,0 +1,14 @@ +import { cn } from "@/lib/utils"; +import { AGENT_LIBRARY_SECTION_PADDING_X } from "../../helpers"; + +type Props = { + children: React.ReactNode; +}; + +export function AnchorLinksWrap({ children }: Props) { + return ( +
+ +
+ ); +} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedActionsWrap.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedActionsWrap.tsx new file mode 100644 index 0000000000..da7985e3e2 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedActionsWrap.tsx @@ -0,0 +1,11 @@ +type Props = { + children: React.ReactNode; +}; + +export function SelectedActionsWrap({ children }: Props) { + return ( +
+ {children} +
+ ); +} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/SelectedRunView.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/SelectedRunView.tsx index 1c7df0f680..97292b85ce 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/SelectedRunView.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/SelectedRunView.tsx @@ -13,10 +13,11 @@ import { import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard"; import { PendingReviewsList } from "@/components/organisms/PendingReviewsList/PendingReviewsList"; import { usePendingReviewsForExecution } from "@/hooks/usePendingReviews"; +import { isLargeScreen, useBreakpoint } from "@/lib/hooks/useBreakpoint"; import { InfoIcon } from "@phosphor-icons/react"; import { useEffect } from "react"; -import { AGENT_LIBRARY_SECTION_PADDING_X } from "../../../helpers"; import { AgentInputsReadOnly } from "../../modals/AgentInputsReadOnly/AgentInputsReadOnly"; +import { AnchorLinksWrap } from "../AnchorLinksWrap"; import { LoadingSelectedContent } from "../LoadingSelectedContent"; import { RunDetailCard } from "../RunDetailCard/RunDetailCard"; import { RunDetailHeader } from "../RunDetailHeader/RunDetailHeader"; @@ -46,6 +47,9 @@ export function SelectedRunView({ const { run, preset, isLoading, responseError, httpError } = useSelectedRunView(agent.graph_id, runId); + const breakpoint = useBreakpoint(); + const isLgScreenUp = isLargeScreen(breakpoint); + const { pendingReviews, isLoading: reviewsLoading, @@ -89,6 +93,15 @@ export function SelectedRunView({
+ {!isLgScreenUp ? ( + + ) : null} + {preset && agent.trigger_setup_info && preset.webhook_id && @@ -100,38 +113,36 @@ export function SelectedRunView({ )} {/* Navigation Links */} -
- -
+ )} + {/* Summary Section */} {withSummary && ( @@ -216,14 +227,16 @@ export function SelectedRunView({
-
- -
+ {isLgScreenUp ? ( +
+ +
+ ) : null}
); } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/components/SelectedRunActions/SelectedRunActions.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/components/SelectedRunActions/SelectedRunActions.tsx index 7cbbd2ff09..7533577bf5 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/components/SelectedRunActions/SelectedRunActions.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/components/SelectedRunActions/SelectedRunActions.tsx @@ -12,6 +12,7 @@ import { StopIcon, } from "@phosphor-icons/react"; import { AgentActionsDropdown } from "../../../AgentActionsDropdown"; +import { SelectedActionsWrap } from "../../../SelectedActionsWrap"; import { ShareRunButton } from "../../../ShareRunButton/ShareRunButton"; import { CreateTemplateModal } from "../CreateTemplateModal/CreateTemplateModal"; import { useSelectedRunActions } from "./useSelectedRunActions"; @@ -49,7 +50,7 @@ export function SelectedRunActions(props: Props) { if (!props.run || !props.agent) return null; return ( -
+ {!isRunning ? (
+ ); } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/SelectedScheduleView.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/SelectedScheduleView.tsx index 841ff04df9..6563e19d5d 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/SelectedScheduleView.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/SelectedScheduleView.tsx @@ -6,9 +6,10 @@ import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner import { Text } from "@/components/atoms/Text/Text"; import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard"; import { humanizeCronExpression } from "@/lib/cron-expression-utils"; +import { isLargeScreen, useBreakpoint } from "@/lib/hooks/useBreakpoint"; import { formatInTimezone, getTimezoneDisplayName } from "@/lib/timezone-utils"; -import { AGENT_LIBRARY_SECTION_PADDING_X } from "../../../helpers"; import { AgentInputsReadOnly } from "../../modals/AgentInputsReadOnly/AgentInputsReadOnly"; +import { AnchorLinksWrap } from "../AnchorLinksWrap"; import { LoadingSelectedContent } from "../LoadingSelectedContent"; import { RunDetailCard } from "../RunDetailCard/RunDetailCard"; import { RunDetailHeader } from "../RunDetailHeader/RunDetailHeader"; @@ -41,6 +42,9 @@ export function SelectedScheduleView({ }, }); + const breakpoint = useBreakpoint(); + const isLgScreenUp = isLargeScreen(breakpoint); + function scrollToSection(id: string) { const element = document.getElementById(id); if (element) { @@ -83,37 +87,42 @@ export function SelectedScheduleView({
-
-
- -
+
+ + {schedule && !isLgScreenUp ? ( +
+ +
+ ) : null}
{/* Navigation Links */} -
- -
+ + + + {/* Schedule Section */}
@@ -172,10 +181,6 @@ export function SelectedScheduleView({
- {/* {// TODO: re-enable edit inputs modal once the API supports it */} - {/* {schedule && Object.keys(schedule.input_data).length > 0 && ( - - )} */}
- {schedule ? ( -
+ {schedule && isLgScreenUp ? ( +
-
+ {openInBuilderHref && (
+ ); } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/components/SelectedTemplateActions.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/components/SelectedTemplateActions.tsx index a3a2a9ac62..1d50ec7c85 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/components/SelectedTemplateActions.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/components/SelectedTemplateActions.tsx @@ -15,6 +15,7 @@ import { useToast } from "@/components/molecules/Toast/use-toast"; import { FloppyDiskIcon, PlayIcon, TrashIcon } from "@phosphor-icons/react"; import { useQueryClient } from "@tanstack/react-query"; import { useState } from "react"; +import { AgentActionsDropdown } from "../../AgentActionsDropdown"; interface Props { agent: LibraryAgent; @@ -134,6 +135,7 @@ export function SelectedTemplateActions({ )} +
)} +
- - - Tasks {runsCount} - - - Scheduled {schedulesCount} - - {triggersCount > 0 && ( - - Triggers {triggersCount} - - )} - - Templates {templatesCount} - - +
+
+
+ + + Tasks {runsCount} + + + Scheduled{" "} + {schedulesCount} + + {triggersCount > 0 && ( + + Triggers{" "} + {triggersCount} + + )} + + Templates{" "} + {templatesCount} + + +
+
<> (
- onSelectRun && onSelectRun(run.id, "runs")} /> @@ -169,6 +180,7 @@ export function SidebarRunsList({
onSelectRun(s.id, "scheduled")} /> @@ -197,6 +209,7 @@ export function SidebarRunsList({
onSelectRun(trigger.id, "triggers")} /> @@ -225,6 +238,7 @@ export function SidebarRunsList({
onSelectRun(template.id, "templates")} /> diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/RunIconWrapper.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/IconWrapper.tsx similarity index 100% rename from autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/RunIconWrapper.tsx rename to autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/IconWrapper.tsx diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/ScheduleActionsDropdown.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/ScheduleActionsDropdown.tsx new file mode 100644 index 0000000000..d85d3ddfaf --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/ScheduleActionsDropdown.tsx @@ -0,0 +1,123 @@ +"use client"; + +import { + getGetV1ListExecutionSchedulesForAGraphQueryOptions, + useDeleteV1DeleteExecutionSchedule, +} from "@/app/api/__generated__/endpoints/schedules/schedules"; +import type { GraphExecutionJobInfo } from "@/app/api/__generated__/models/graphExecutionJobInfo"; +import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; +import { Button } from "@/components/atoms/Button/Button"; +import { Text } from "@/components/atoms/Text/Text"; +import { Dialog } from "@/components/molecules/Dialog/Dialog"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/molecules/DropdownMenu/DropdownMenu"; +import { useToast } from "@/components/molecules/Toast/use-toast"; +import { DotsThreeVertical } from "@phosphor-icons/react"; +import { useQueryClient } from "@tanstack/react-query"; +import { useState } from "react"; + +interface Props { + agent: LibraryAgent; + schedule: GraphExecutionJobInfo; + onDeleted?: () => void; +} + +export function ScheduleActionsDropdown({ agent, schedule, onDeleted }: Props) { + const { toast } = useToast(); + const queryClient = useQueryClient(); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + + const { mutateAsync: deleteSchedule, isPending: isDeleting } = + useDeleteV1DeleteExecutionSchedule(); + + async function handleDelete() { + try { + await deleteSchedule({ scheduleId: schedule.id }); + + toast({ title: "Schedule deleted" }); + + queryClient.invalidateQueries({ + queryKey: getGetV1ListExecutionSchedulesForAGraphQueryOptions( + agent.graph_id, + ).queryKey, + }); + + setShowDeleteDialog(false); + onDeleted?.(); + } catch (error: unknown) { + toast({ + title: "Failed to delete schedule", + description: + error instanceof Error + ? error.message + : "An unexpected error occurred.", + variant: "destructive", + }); + } + } + + return ( + <> + + + + + + { + e.stopPropagation(); + setShowDeleteDialog(true); + }} + className="flex items-center gap-2" + > + Delete schedule + + + + + + +
+ + Are you sure you want to delete this schedule? This action cannot + be undone. + + + + + +
+
+
+ + ); +} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/ScheduleListItem.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/ScheduleListItem.tsx index 2265a92f62..a389fb4fc8 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/ScheduleListItem.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/ScheduleListItem.tsx @@ -1,24 +1,30 @@ "use client"; import { GraphExecutionJobInfo } from "@/app/api/__generated__/models/graphExecutionJobInfo"; +import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { ClockClockwiseIcon } from "@phosphor-icons/react"; import moment from "moment"; -import { IconWrapper } from "./RunIconWrapper"; -import { RunSidebarCard } from "./RunSidebarCard"; +import { IconWrapper } from "./IconWrapper"; +import { ScheduleActionsDropdown } from "./ScheduleActionsDropdown"; +import { SidebarItemCard } from "./SidebarItemCard"; -interface ScheduleListItemProps { +interface Props { schedule: GraphExecutionJobInfo; + agent: LibraryAgent; selected?: boolean; onClick?: () => void; + onDeleted?: () => void; } export function ScheduleListItem({ schedule, + agent, selected, onClick, -}: ScheduleListItemProps) { + onDeleted, +}: Props) { return ( - } + actions={ + + } /> ); } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/RunSidebarCard.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/SidebarItemCard.tsx similarity index 68% rename from autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/RunSidebarCard.tsx rename to autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/SidebarItemCard.tsx index eb163f7337..4f4e9962ce 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/RunSidebarCard.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/SidebarItemCard.tsx @@ -4,25 +4,27 @@ import { Text } from "@/components/atoms/Text/Text"; import { cn } from "@/lib/utils"; import React from "react"; -interface RunListItemProps { +interface Props { title: string; description?: string; icon?: React.ReactNode; selected?: boolean; onClick?: () => void; + actions?: React.ReactNode; } -export function RunSidebarCard({ +export function SidebarItemCard({ title, description, icon, selected, onClick, -}: RunListItemProps) { + actions, +}: Props) { return ( -
+ {actions ? ( +
e.stopPropagation()}>{actions}
+ ) : null}
- +
); } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TaskActionsDropdown.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TaskActionsDropdown.tsx new file mode 100644 index 0000000000..95cc7740f8 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TaskActionsDropdown.tsx @@ -0,0 +1,185 @@ +"use client"; + +import { + getGetV1ListGraphExecutionsInfiniteQueryOptions, + useDeleteV1DeleteGraphExecution, +} from "@/app/api/__generated__/endpoints/graphs/graphs"; +import { + getGetV2ListPresetsQueryKey, + usePostV2CreateANewPreset, +} from "@/app/api/__generated__/endpoints/presets/presets"; +import type { GraphExecutionMeta } from "@/app/api/__generated__/models/graphExecutionMeta"; +import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; +import { Button } from "@/components/atoms/Button/Button"; +import { Text } from "@/components/atoms/Text/Text"; +import { Dialog } from "@/components/molecules/Dialog/Dialog"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/molecules/DropdownMenu/DropdownMenu"; +import { useToast } from "@/components/molecules/Toast/use-toast"; +import { DotsThreeVertical } from "@phosphor-icons/react"; +import { useQueryClient } from "@tanstack/react-query"; +import { useState } from "react"; +import { CreateTemplateModal } from "../../../selected-views/SelectedRunView/components/CreateTemplateModal/CreateTemplateModal"; + +interface Props { + agent: LibraryAgent; + run: GraphExecutionMeta; + onDeleted?: () => void; +} + +export function TaskActionsDropdown({ agent, run, onDeleted }: Props) { + const { toast } = useToast(); + const queryClient = useQueryClient(); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [isCreateTemplateModalOpen, setIsCreateTemplateModalOpen] = + useState(false); + + const { mutateAsync: deleteRun, isPending: isDeletingRun } = + useDeleteV1DeleteGraphExecution(); + + const { mutateAsync: createPreset } = usePostV2CreateANewPreset(); + + async function handleDeleteRun() { + try { + await deleteRun({ graphExecId: run.id }); + + toast({ title: "Task deleted" }); + + await queryClient.refetchQueries({ + queryKey: getGetV1ListGraphExecutionsInfiniteQueryOptions( + agent.graph_id, + ).queryKey, + }); + + setShowDeleteDialog(false); + onDeleted?.(); + } catch (error: unknown) { + toast({ + title: "Failed to delete task", + description: + error instanceof Error + ? error.message + : "An unexpected error occurred.", + variant: "destructive", + }); + } + } + + async function handleCreateTemplate(name: string, description: string) { + try { + const res = await createPreset({ + data: { + name, + description, + graph_execution_id: run.id, + }, + }); + + if (res.status === 200) { + toast({ + title: "Template created", + }); + + queryClient.invalidateQueries({ + queryKey: getGetV2ListPresetsQueryKey({ + graph_id: agent.graph_id, + }), + }); + + setIsCreateTemplateModalOpen(false); + } + } catch (error: unknown) { + toast({ + title: "Failed to create template", + description: + error instanceof Error + ? error.message + : "An unexpected error occurred.", + variant: "destructive", + }); + } + } + + return ( + <> + + + + + + { + e.stopPropagation(); + setIsCreateTemplateModalOpen(true); + }} + className="flex items-center gap-2" + > + Save as template + + + { + e.stopPropagation(); + setShowDeleteDialog(true); + }} + className="flex items-center gap-2" + > + Delete task + + + + + + +
+ + Are you sure you want to delete this task? This action cannot be + undone. + + + + + +
+
+
+ + setIsCreateTemplateModalOpen(false)} + onCreate={handleCreateTemplate} + run={run as any} + /> + + ); +} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/RunListItem.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TaskListItem.tsx similarity index 80% rename from autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/RunListItem.tsx rename to autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TaskListItem.tsx index c038217f72..22adc54e4f 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/RunListItem.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TaskListItem.tsx @@ -2,6 +2,7 @@ import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus"; import { GraphExecutionMeta } from "@/app/api/__generated__/models/graphExecutionMeta"; +import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { CheckCircleIcon, ClockIcon, @@ -12,8 +13,9 @@ import { } from "@phosphor-icons/react"; import moment from "moment"; import React from "react"; -import { IconWrapper } from "./RunIconWrapper"; -import { RunSidebarCard } from "./RunSidebarCard"; +import { IconWrapper } from "./IconWrapper"; +import { SidebarItemCard } from "./SidebarItemCard"; +import { TaskActionsDropdown } from "./TaskActionsDropdown"; const statusIconMap: Record = { INCOMPLETE: ( @@ -53,26 +55,33 @@ const statusIconMap: Record = { ), }; -interface RunListItemProps { +interface Props { run: GraphExecutionMeta; title: string; + agent: LibraryAgent; selected?: boolean; onClick?: () => void; + onDeleted?: () => void; } -export function RunListItem({ +export function TaskListItem({ run, title, + agent, selected, onClick, -}: RunListItemProps) { + onDeleted, +}: Props) { return ( - + } /> ); } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TemplateActionsDropdown.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TemplateActionsDropdown.tsx new file mode 100644 index 0000000000..b65e0fd44a --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TemplateActionsDropdown.tsx @@ -0,0 +1,125 @@ +"use client"; + +import { + getGetV2ListPresetsQueryKey, + useDeleteV2DeleteAPreset, +} from "@/app/api/__generated__/endpoints/presets/presets"; +import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; +import type { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset"; +import { Button } from "@/components/atoms/Button/Button"; +import { Text } from "@/components/atoms/Text/Text"; +import { Dialog } from "@/components/molecules/Dialog/Dialog"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/molecules/DropdownMenu/DropdownMenu"; +import { useToast } from "@/components/molecules/Toast/use-toast"; +import { DotsThreeVertical } from "@phosphor-icons/react"; +import { useQueryClient } from "@tanstack/react-query"; +import { useState } from "react"; + +interface Props { + agent: LibraryAgent; + template: LibraryAgentPreset; + onDeleted?: () => void; +} + +export function TemplateActionsDropdown({ agent, template, onDeleted }: Props) { + const { toast } = useToast(); + const queryClient = useQueryClient(); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + + const { mutateAsync: deletePreset, isPending: isDeleting } = + useDeleteV2DeleteAPreset(); + + async function handleDelete() { + try { + await deletePreset({ presetId: template.id }); + + toast({ + title: "Template deleted", + }); + + queryClient.invalidateQueries({ + queryKey: getGetV2ListPresetsQueryKey({ + graph_id: agent.graph_id, + }), + }); + + setShowDeleteDialog(false); + onDeleted?.(); + } catch (error: unknown) { + toast({ + title: "Failed to delete template", + description: + error instanceof Error + ? error.message + : "An unexpected error occurred.", + variant: "destructive", + }); + } + } + + return ( + <> + + + + + + { + e.stopPropagation(); + setShowDeleteDialog(true); + }} + className="flex items-center gap-2" + > + Delete template + + + + + + +
+ + Are you sure you want to delete this template? This action cannot + be undone. + + + + + +
+
+
+ + ); +} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TemplateListItem.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TemplateListItem.tsx index ffdd746416..c970cd1522 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TemplateListItem.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TemplateListItem.tsx @@ -1,24 +1,30 @@ "use client"; +import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset"; import { FileTextIcon } from "@phosphor-icons/react"; import moment from "moment"; -import { IconWrapper } from "./RunIconWrapper"; -import { RunSidebarCard } from "./RunSidebarCard"; +import { IconWrapper } from "./IconWrapper"; +import { SidebarItemCard } from "./SidebarItemCard"; +import { TemplateActionsDropdown } from "./TemplateActionsDropdown"; -interface TemplateListItemProps { +interface Props { template: LibraryAgentPreset; + agent: LibraryAgent; selected?: boolean; onClick?: () => void; + onDeleted?: () => void; } export function TemplateListItem({ template, + agent, selected, onClick, -}: TemplateListItemProps) { + onDeleted, +}: Props) { return ( - @@ -28,6 +34,13 @@ export function TemplateListItem({ description={moment(template.updated_at).fromNow()} onClick={onClick} selected={selected} + actions={ + + } /> ); } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TriggerActionsDropdown.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TriggerActionsDropdown.tsx new file mode 100644 index 0000000000..35296948c1 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TriggerActionsDropdown.tsx @@ -0,0 +1,125 @@ +"use client"; + +import { + getGetV2ListPresetsQueryKey, + useDeleteV2DeleteAPreset, +} from "@/app/api/__generated__/endpoints/presets/presets"; +import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; +import type { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset"; +import { Button } from "@/components/atoms/Button/Button"; +import { Text } from "@/components/atoms/Text/Text"; +import { Dialog } from "@/components/molecules/Dialog/Dialog"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/molecules/DropdownMenu/DropdownMenu"; +import { useToast } from "@/components/molecules/Toast/use-toast"; +import { DotsThreeVertical } from "@phosphor-icons/react"; +import { useQueryClient } from "@tanstack/react-query"; +import { useState } from "react"; + +interface Props { + agent: LibraryAgent; + trigger: LibraryAgentPreset; + onDeleted?: () => void; +} + +export function TriggerActionsDropdown({ agent, trigger, onDeleted }: Props) { + const { toast } = useToast(); + const queryClient = useQueryClient(); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + + const { mutateAsync: deletePreset, isPending: isDeleting } = + useDeleteV2DeleteAPreset(); + + async function handleDelete() { + try { + await deletePreset({ presetId: trigger.id }); + + toast({ + title: "Trigger deleted", + }); + + queryClient.invalidateQueries({ + queryKey: getGetV2ListPresetsQueryKey({ + graph_id: agent.graph_id, + }), + }); + + setShowDeleteDialog(false); + onDeleted?.(); + } catch (error: unknown) { + toast({ + title: "Failed to delete trigger", + description: + error instanceof Error + ? error.message + : "An unexpected error occurred.", + variant: "destructive", + }); + } + } + + return ( + <> + + + + + + { + e.stopPropagation(); + setShowDeleteDialog(true); + }} + className="flex items-center gap-2" + > + Delete trigger + + + + + + +
+ + Are you sure you want to delete this trigger? This action cannot + be undone. + + + + + +
+
+
+ + ); +} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TriggerListItem.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TriggerListItem.tsx index a5d339ad36..4c399e640a 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TriggerListItem.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TriggerListItem.tsx @@ -1,24 +1,30 @@ "use client"; +import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset"; import { LightningIcon } from "@phosphor-icons/react"; import moment from "moment"; -import { IconWrapper } from "./RunIconWrapper"; -import { RunSidebarCard } from "./RunSidebarCard"; +import { IconWrapper } from "./IconWrapper"; +import { SidebarItemCard } from "./SidebarItemCard"; +import { TriggerActionsDropdown } from "./TriggerActionsDropdown"; -interface TriggerListItemProps { +interface Props { trigger: LibraryAgentPreset; + agent: LibraryAgent; selected?: boolean; onClick?: () => void; + onDeleted?: () => void; } export function TriggerListItem({ trigger, + agent, selected, onClick, -}: TriggerListItemProps) { + onDeleted, +}: Props) { return ( - @@ -28,6 +34,13 @@ export function TriggerListItem({ description={moment(trigger.updated_at).fromNow()} onClick={onClick} selected={selected} + actions={ + + } /> ); } diff --git a/autogpt_platform/frontend/src/components/__legacy__/ui/skeleton.tsx b/autogpt_platform/frontend/src/components/__legacy__/ui/skeleton.tsx index 869263d5f0..805fedddcc 100644 --- a/autogpt_platform/frontend/src/components/__legacy__/ui/skeleton.tsx +++ b/autogpt_platform/frontend/src/components/__legacy__/ui/skeleton.tsx @@ -6,7 +6,7 @@ function Skeleton({ }: React.HTMLAttributes) { return (
); diff --git a/autogpt_platform/frontend/src/components/atoms/Button/helpers.ts b/autogpt_platform/frontend/src/components/atoms/Button/helpers.ts index db7938661c..4d9706838c 100644 --- a/autogpt_platform/frontend/src/components/atoms/Button/helpers.ts +++ b/autogpt_platform/frontend/src/components/atoms/Button/helpers.ts @@ -16,7 +16,7 @@ export const extendedButtonVariants = cva( primary: "bg-zinc-800 border-zinc-800 text-white hover:bg-zinc-900 hover:border-zinc-900 rounded-full disabled:text-white disabled:bg-zinc-200 disabled:border-zinc-200 disabled:opacity-1", secondary: - "bg-zinc-100 border-zinc-100 text-black hover:bg-zinc-300 hover:border-zinc-300 rounded-full disabled:text-zinc-300 disabled:bg-zinc-50 disabled:border-zinc-50 disabled:opacity-1", + "bg-zinc-200 border-zinc-200 text-black hover:bg-zinc-300 hover:border-zinc-300 rounded-full disabled:text-zinc-300 disabled:bg-zinc-50 disabled:border-zinc-50 disabled:opacity-1", destructive: "bg-red-500 border-red-500 text-white hover:bg-red-600 hover:border-red-600 rounded-full disabled:text-white disabled:bg-zinc-200 disabled:border-zinc-200 disabled:opacity-1", outline: diff --git a/autogpt_platform/frontend/src/components/molecules/Dialog/components/DrawerWrap.tsx b/autogpt_platform/frontend/src/components/molecules/Dialog/components/DrawerWrap.tsx index b9d3b2e118..d00817bf59 100644 --- a/autogpt_platform/frontend/src/components/molecules/Dialog/components/DrawerWrap.tsx +++ b/autogpt_platform/frontend/src/components/molecules/Dialog/components/DrawerWrap.tsx @@ -1,4 +1,6 @@ import { Button } from "@/components/__legacy__/ui/button"; +import { scrollbarStyles } from "@/components/styles/scrollbars"; +import { cn } from "@/lib/utils"; import { X } from "@phosphor-icons/react"; import { PropsWithChildren } from "react"; import { Drawer } from "vaul"; @@ -41,7 +43,7 @@ export function DrawerWrap({ onInteractOutside={handleClose} >
@@ -61,7 +63,16 @@ export function DrawerWrap({ ) ) : null}
-
{children}
+
+
+ {children} +
+
); diff --git a/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.ts b/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.ts index b04dcdd193..3b7d12e8e9 100644 --- a/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.ts +++ b/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.ts @@ -19,5 +19,5 @@ export const modalStyles = { // Drawer specific styles export const drawerStyles = { ...commonStyles, - content: `${commonStyles.content} max-h-[90vh] w-full bottom-0 rounded-br-none rounded-bl-none`, + content: `${commonStyles.content} max-h-[90vh] w-full bottom-0 rounded-br-none rounded-bl-none min-h-0`, };