mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
Merge branch 'dev' into swiftyos/sdk
This commit is contained in:
@@ -127,7 +127,7 @@ class LibraryAgent(pydantic.BaseModel):
|
||||
description=graph.description,
|
||||
input_schema=graph.input_schema,
|
||||
credentials_input_schema=(
|
||||
graph.credentials_input_schema if sub_graphs else None
|
||||
graph.credentials_input_schema if sub_graphs is not None else None
|
||||
),
|
||||
has_external_trigger=graph.has_webhook_trigger,
|
||||
trigger_setup_info=(
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
"react-shepherd": "6.1.8",
|
||||
"recharts": "2.15.3",
|
||||
"shepherd.js": "14.5.0",
|
||||
"sonner": "2.0.6",
|
||||
"tailwind-merge": "2.6.0",
|
||||
"tailwindcss-animate": "1.0.7",
|
||||
"uuid": "11.1.0",
|
||||
|
||||
14
autogpt_platform/frontend/pnpm-lock.yaml
generated
14
autogpt_platform/frontend/pnpm-lock.yaml
generated
@@ -191,6 +191,9 @@ importers:
|
||||
shepherd.js:
|
||||
specifier: 14.5.0
|
||||
version: 14.5.0
|
||||
sonner:
|
||||
specifier: 2.0.6
|
||||
version: 2.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
tailwind-merge:
|
||||
specifier: 2.6.0
|
||||
version: 2.6.0
|
||||
@@ -6376,6 +6379,12 @@ packages:
|
||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
sonner@2.0.6:
|
||||
resolution: {integrity: sha512-yHFhk8T/DK3YxjFQXIrcHT1rGEeTLliVzWbO0xN8GberVun2RiBnxAjXAYpZrqwEVHBG9asI/Li8TAAhN9m59Q==}
|
||||
peerDependencies:
|
||||
react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||
react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -14194,6 +14203,11 @@ snapshots:
|
||||
|
||||
slash@3.0.0: {}
|
||||
|
||||
sonner@2.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
|
||||
source-map-support@0.5.21:
|
||||
|
||||
@@ -11,7 +11,7 @@ import StarRating from "@/components/onboarding/StarRating";
|
||||
import SchemaTooltip from "@/components/SchemaTooltip";
|
||||
import { TypeBasedInput } from "@/components/type-based-input";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { GraphMeta, StoreAgentDetails } from "@/lib/autogpt-server-api";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -41,7 +41,7 @@ import {
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import LoadingBox, { LoadingSpinner } from "@/components/ui/loading";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
|
||||
export default function AgentRunsPage(): React.ReactElement {
|
||||
const { id: agentID }: { id: LibraryAgentID } = useParams();
|
||||
|
||||
@@ -4,7 +4,7 @@ import { z } from "zod";
|
||||
import { uploadAgentFormSchema } from "./LibraryUploadAgentDialog";
|
||||
import { usePostV1CreateNewGraph } from "@/app/api/__generated__/endpoints/graphs/graphs";
|
||||
import { GraphModel } from "@/app/api/__generated__/models/graphModel";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { useState } from "react";
|
||||
import { Graph } from "@/app/api/__generated__/models/graph";
|
||||
import { sanitizeImportedGraph } from "@/lib/autogpt-server-api";
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
useGetV1ListUserApiKeys,
|
||||
} from "@/app/api/__generated__/endpoints/api-keys/api-keys";
|
||||
import { APIKeyWithoutHash } from "@/app/api/__generated__/models/aPIKeyWithoutHash";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { getQueryClient } from "@/lib/react-query/queryClient";
|
||||
|
||||
export const useAPISection = () => {
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
} from "@/app/api/__generated__/endpoints/api-keys/api-keys";
|
||||
import { APIKeyPermission } from "@/app/api/__generated__/models/aPIKeyPermission";
|
||||
import { CreateAPIKeyResponse } from "@/app/api/__generated__/models/createAPIKeyResponse";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { getQueryClient } from "@/lib/react-query/queryClient";
|
||||
import { useState } from "react";
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@ import { Button } from "@/components/ui/button";
|
||||
import useCredits from "@/hooks/useCredits";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { useSearchParams, useRouter } from "next/navigation";
|
||||
import { useToast, useToastOnFail } from "@/components/ui/use-toast";
|
||||
import {
|
||||
useToast,
|
||||
useToastOnFail,
|
||||
} from "@/components/molecules/Toast/use-toast";
|
||||
|
||||
import { RefundModal } from "./RefundModal";
|
||||
import { CreditTransaction } from "@/lib/autogpt-server-api";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { IconKey, IconUser } from "@/components/ui/icons";
|
||||
import { Trash2Icon } from "lucide-react";
|
||||
import { KeyIcon } from "@phosphor-icons/react/dist/ssr";
|
||||
|
||||
@@ -4,7 +4,7 @@ import { createDefaultValues, formSchema } from "./helper";
|
||||
import { z } from "zod";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { updateSettings } from "../../actions";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { NotificationPreference } from "@/app/api/__generated__/models/notificationPreference";
|
||||
import { User } from "@supabase/supabase-js";
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import LoadingBox from "@/components/ui/loading";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { useTurnstile } from "@/hooks/useTurnstile";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import { getBehaveAs } from "@/lib/utils";
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React from "react";
|
||||
import type { Metadata } from "next";
|
||||
import { fonts } from "@/components/styles/fonts";
|
||||
import type { Metadata } from "next";
|
||||
import React from "react";
|
||||
|
||||
import "./globals.css";
|
||||
|
||||
import { Toaster } from "@/components/ui/toaster";
|
||||
import { Providers } from "@/app/providers";
|
||||
import TallyPopupSimple from "@/components/TallyPopup";
|
||||
import { GoogleAnalytics } from "@/components/analytics/google-analytics";
|
||||
import { Toaster } from "@/components/molecules/Toast/toaster";
|
||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "./ui/table";
|
||||
import { useToast } from "./ui/use-toast";
|
||||
import { useToast } from "./molecules/Toast/use-toast";
|
||||
|
||||
type DataTableProps = {
|
||||
title?: string;
|
||||
|
||||
@@ -56,7 +56,7 @@ import RunnerUIWrapper, {
|
||||
import { CronSchedulerDialog } from "@/components/cron-scheduler-dialog";
|
||||
import PrimaryActionBar from "@/components/PrimaryActionButton";
|
||||
import OttoChatWidget from "@/components/OttoChatWidget";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { useCopyPaste } from "../hooks/useCopyPaste";
|
||||
|
||||
// This is for the history, this is the minimum distance a block must move before it is logged
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Button } from "./ui/button";
|
||||
import { Textarea } from "./ui/textarea";
|
||||
import { Maximize2, Minimize2, Clipboard } from "lucide-react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { toast } from "./ui/use-toast";
|
||||
import { toast } from "./molecules/Toast/use-toast";
|
||||
|
||||
interface ModalProps {
|
||||
isOpen: boolean;
|
||||
|
||||
@@ -18,7 +18,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { IconRefresh, IconSquare } from "@/components/ui/icons";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import LoadingBox from "@/components/ui/loading";
|
||||
import { useToastOnFail } from "@/components/ui/use-toast";
|
||||
import { useToastOnFail } from "@/components/molecules/Toast/use-toast";
|
||||
|
||||
import {
|
||||
AgentRunStatus,
|
||||
|
||||
@@ -22,7 +22,10 @@ import { TypeBasedInput } from "@/components/type-based-input";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { IconCross, IconPlay, IconSave } from "@/components/ui/icons";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { useToast, useToastOnFail } from "@/components/ui/use-toast";
|
||||
import {
|
||||
useToast,
|
||||
useToastOnFail,
|
||||
} from "@/components/molecules/Toast/use-toast";
|
||||
import { isEmpty } from "lodash";
|
||||
import { CalendarClockIcon, Trash2Icon } from "lucide-react";
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { IconCross } from "@/components/ui/icons";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import LoadingBox from "@/components/ui/loading";
|
||||
import { useToastOnFail } from "@/components/ui/use-toast";
|
||||
import { useToastOnFail } from "@/components/molecules/Toast/use-toast";
|
||||
import { humanizeCronExpression } from "@/lib/cron-expression-utils";
|
||||
import { PlayIcon } from "lucide-react";
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Separator } from "@/components/ui/separator";
|
||||
import BackendAPI, { LibraryAgent } from "@/lib/autogpt-server-api";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
|
||||
import { useOnboarding } from "../onboarding/onboarding-provider";
|
||||
import { User } from "@supabase/supabase-js";
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as Sentry from "@sentry/nextjs";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useTransition } from "react";
|
||||
import { LoadingSpinner } from "../ui/loading";
|
||||
import { toast } from "../ui/use-toast";
|
||||
import { toast } from "../molecules/Toast/use-toast";
|
||||
|
||||
export function ProfilePopoutMenuLogoutButton() {
|
||||
const router = useRouter();
|
||||
|
||||
@@ -5,7 +5,7 @@ import Image from "next/image";
|
||||
import { Button } from "../agptui/Button";
|
||||
import { IconCross, IconPlus } from "../ui/icons";
|
||||
import BackendAPI from "@/lib/autogpt-server-api";
|
||||
import { toast } from "../ui/use-toast";
|
||||
import { toast } from "../molecules/Toast/use-toast";
|
||||
|
||||
export interface PublishAgentInfoInitialData {
|
||||
agent_id: string;
|
||||
@@ -133,6 +133,7 @@ export const PublishAgentInfo: React.FC<PublishAgentInfoProps> = ({
|
||||
toast({
|
||||
title: "Failed to upload image",
|
||||
description: `Error: ${error}`,
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "../ui/input";
|
||||
import Link from "next/link";
|
||||
import { useToast, useToastOnFail } from "../ui/use-toast";
|
||||
import { useToast, useToastOnFail } from "../molecules/Toast/use-toast";
|
||||
import useCredits from "@/hooks/useCredits";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
@@ -88,7 +88,10 @@ export default function WalletRefill() {
|
||||
setIsLoading(true);
|
||||
await updateAutoTopUpConfig(data.refillAmount * 100, data.threshold * 100)
|
||||
.then(() => {
|
||||
toast({ title: "Auto top-up config updated! 🎉" });
|
||||
toast({
|
||||
title: "Auto top-up config updated! 🎉",
|
||||
variant: "success",
|
||||
});
|
||||
})
|
||||
.catch(toastOnFail("update auto top-up config"));
|
||||
setIsLoading(false);
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Button } from "../Button";
|
||||
import { MyAgentsResponse } from "@/lib/autogpt-server-api";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { StoreSubmissionRequest } from "@/app/api/__generated__/models/storeSubmissionRequest";
|
||||
interface PublishAgentPopoutProps {
|
||||
trigger?: React.ReactNode;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { CronScheduler } from "@/components/cron-scheduler";
|
||||
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
|
||||
interface SaveControlProps {
|
||||
agentMeta: GraphMeta | null;
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
UserPasswordCredentials,
|
||||
} from "@/lib/autogpt-server-api";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { useToastOnFail } from "@/components/ui/use-toast";
|
||||
import { useToastOnFail } from "@/components/molecules/Toast/use-toast";
|
||||
import { toDisplayName } from "@/components/integrations/helper";
|
||||
|
||||
type APIKeyCredentialsCreatable = Omit<
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Custom toast styling. It's here to override the Sonner default styles via CSS specificity */
|
||||
html body .toastDefault,
|
||||
html body .toastInfo {
|
||||
background: #3e3e43 !important;
|
||||
border-color: #3e3e43 !important;
|
||||
}
|
||||
|
||||
html body .toastSuccess {
|
||||
background: #45b56e !important;
|
||||
border-color: #45b56e !important;
|
||||
}
|
||||
|
||||
html body .toastWarning {
|
||||
background: #e77b00 !important;
|
||||
border-color: #e77b00 !important;
|
||||
}
|
||||
|
||||
html body .toastError {
|
||||
background: #f26969 !important;
|
||||
border-color: #f26969 !important;
|
||||
}
|
||||
|
||||
html body .toastTitle {
|
||||
color: #fff !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
html body .toastDescription {
|
||||
color: #fff !important;
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { toast } from "@/components/molecules/Toast/use-toast";
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { Toaster } from "./toaster";
|
||||
|
||||
const meta = {
|
||||
title: "Molecules/Toast",
|
||||
component: Toaster,
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
} satisfies Meta<typeof Toaster>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
// Helper component to demonstrate toast functionality
|
||||
function ToastDemo() {
|
||||
function handleDefaultToast() {
|
||||
toast({
|
||||
title: "Default Toast",
|
||||
description: "This is a default toast message.",
|
||||
});
|
||||
}
|
||||
|
||||
function handleSuccessToast() {
|
||||
toast({
|
||||
title: "Success!",
|
||||
description: "Your operation was completed successfully.",
|
||||
variant: "success",
|
||||
});
|
||||
}
|
||||
|
||||
function handleDestructiveToast() {
|
||||
toast({
|
||||
title: "Error!",
|
||||
description: "Something went wrong. Please try again.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
|
||||
function handleInfoToast() {
|
||||
toast({
|
||||
title: "Information",
|
||||
description: "Here's some helpful information for you.",
|
||||
variant: "info",
|
||||
});
|
||||
}
|
||||
|
||||
function handleToastWithAction() {
|
||||
toast({
|
||||
title: "Toast with Action",
|
||||
description: "This toast has a custom action button.",
|
||||
action: (
|
||||
<Button variant="secondary" size="small">
|
||||
Action
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
function handlePersistentToast() {
|
||||
toast({
|
||||
title: "Persistent Toast",
|
||||
description: "This toast won't auto-dismiss.",
|
||||
dismissable: false,
|
||||
});
|
||||
}
|
||||
|
||||
function handleLongDurationToast() {
|
||||
toast({
|
||||
title: "Long Duration Toast",
|
||||
description: "This toast stays visible for 10 seconds.",
|
||||
duration: 10000,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4 p-8">
|
||||
<h2 className="text-2xl font-bold">Toast Examples</h2>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<Button onClick={handleDefaultToast}>Default Toast</Button>
|
||||
<Button onClick={handleSuccessToast}>Success Toast</Button>
|
||||
<Button onClick={handleDestructiveToast}>Error Toast</Button>
|
||||
<Button onClick={handleInfoToast}>Info Toast</Button>
|
||||
<Button onClick={handleToastWithAction}>Toast with Action</Button>
|
||||
<Button onClick={handlePersistentToast}>Persistent Toast</Button>
|
||||
<Button onClick={handleLongDurationToast}>Long Duration Toast</Button>
|
||||
</div>
|
||||
<Toaster />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const Default: Story = {
|
||||
render: () => <ToastDemo />,
|
||||
};
|
||||
|
||||
export const SuccessToast: Story = {
|
||||
render: () => (
|
||||
<div className="p-8">
|
||||
<Button
|
||||
onClick={() =>
|
||||
toast({
|
||||
title: "Success!",
|
||||
description: "Your operation was completed successfully.",
|
||||
variant: "success",
|
||||
})
|
||||
}
|
||||
>
|
||||
Show Success Toast
|
||||
</Button>
|
||||
<Toaster />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export const ErrorToast: Story = {
|
||||
render: () => (
|
||||
<div className="p-8">
|
||||
<Button
|
||||
onClick={() =>
|
||||
toast({
|
||||
title: "Error!",
|
||||
description: "Something went wrong. Please try again.",
|
||||
variant: "destructive",
|
||||
})
|
||||
}
|
||||
>
|
||||
Show Error Toast
|
||||
</Button>
|
||||
<Toaster />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export const InfoToast: Story = {
|
||||
render: () => (
|
||||
<div className="p-8">
|
||||
<Button
|
||||
onClick={() =>
|
||||
toast({
|
||||
title: "Information",
|
||||
description: "Here's some helpful information for you.",
|
||||
variant: "info",
|
||||
})
|
||||
}
|
||||
>
|
||||
Show Info Toast
|
||||
</Button>
|
||||
<Toaster />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export const ToastWithAction: Story = {
|
||||
render: () => (
|
||||
<div className="p-8">
|
||||
<Button
|
||||
onClick={() =>
|
||||
toast({
|
||||
title: "Toast with Action",
|
||||
description: "This toast has a custom action button.",
|
||||
action: (
|
||||
<Button variant="secondary" size="small">
|
||||
Action
|
||||
</Button>
|
||||
),
|
||||
})
|
||||
}
|
||||
>
|
||||
Show Toast with Action
|
||||
</Button>
|
||||
<Toaster />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export const PersistentToast: Story = {
|
||||
render: () => (
|
||||
<div className="p-8">
|
||||
<Button
|
||||
onClick={() =>
|
||||
toast({
|
||||
title: "Persistent Toast",
|
||||
description: "This toast won't auto-dismiss. Click the X to close.",
|
||||
dismissable: false,
|
||||
})
|
||||
}
|
||||
>
|
||||
Show Persistent Toast
|
||||
</Button>
|
||||
<Toaster />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
"use client";
|
||||
|
||||
import { Toaster as SonnerToaster } from "sonner";
|
||||
import { CheckCircle, XCircle, Warning, Info } from "@phosphor-icons/react";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export function Toaster() {
|
||||
return (
|
||||
<SonnerToaster
|
||||
position="bottom-center"
|
||||
richColors
|
||||
toastOptions={{
|
||||
classNames: {
|
||||
toast: styles.toastDefault,
|
||||
title: styles.toastTitle,
|
||||
description: styles.toastDescription,
|
||||
error: styles.toastError,
|
||||
success: styles.toastSuccess,
|
||||
warning: styles.toastWarning,
|
||||
info: styles.toastInfo,
|
||||
},
|
||||
}}
|
||||
icons={{
|
||||
success: <CheckCircle className="h-5 w-5" color="#fff" />,
|
||||
error: <XCircle className="h-5 w-5" color="#fff" />,
|
||||
warning: <Warning className="h-5 w-5" color="#fff" />,
|
||||
info: <Info className="h-5 w-5" color="#fff" />,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { toast as sonnerToast } from "sonner";
|
||||
|
||||
export interface ToastProps {
|
||||
title?: React.ReactNode;
|
||||
description?: React.ReactNode;
|
||||
variant?: "default" | "destructive" | "success" | "info";
|
||||
duration?: number;
|
||||
action?: React.ReactNode;
|
||||
dismissable?: boolean;
|
||||
}
|
||||
|
||||
type ToasterToast = ToastProps & {
|
||||
id: string;
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
};
|
||||
|
||||
interface State {
|
||||
toasts: ToasterToast[];
|
||||
}
|
||||
|
||||
type Toast = Omit<ToasterToast, "id">;
|
||||
|
||||
function toast({
|
||||
title,
|
||||
description,
|
||||
variant = "default",
|
||||
duration = 5000,
|
||||
action,
|
||||
dismissable = true,
|
||||
..._props
|
||||
}: Toast) {
|
||||
const message = title || description || "";
|
||||
const descriptionText = title && description ? description : undefined;
|
||||
|
||||
const toastOptions = {
|
||||
duration: dismissable ? duration : Infinity,
|
||||
action,
|
||||
description: descriptionText,
|
||||
};
|
||||
|
||||
let toastId: string | number;
|
||||
|
||||
switch (variant) {
|
||||
case "destructive":
|
||||
toastId = sonnerToast.error(message, toastOptions);
|
||||
break;
|
||||
case "success":
|
||||
toastId = sonnerToast.success(message, toastOptions);
|
||||
break;
|
||||
case "info":
|
||||
toastId = sonnerToast.info(message, toastOptions);
|
||||
break;
|
||||
default:
|
||||
toastId = sonnerToast(message, toastOptions);
|
||||
}
|
||||
|
||||
const id = toastId.toString();
|
||||
|
||||
const update = (newProps: ToasterToast) => {
|
||||
sonnerToast.dismiss(toastId);
|
||||
return toast(newProps);
|
||||
};
|
||||
|
||||
const dismiss = () => sonnerToast.dismiss(toastId);
|
||||
|
||||
return {
|
||||
id,
|
||||
dismiss,
|
||||
update,
|
||||
};
|
||||
}
|
||||
|
||||
function useToast() {
|
||||
const [state] = React.useState<State>({ toasts: [] });
|
||||
|
||||
return {
|
||||
...state,
|
||||
toast,
|
||||
dismiss: (toastId?: string) => {
|
||||
if (toastId) {
|
||||
sonnerToast.dismiss(toastId);
|
||||
} else {
|
||||
sonnerToast.dismiss();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
interface ToastOnFailOptions {
|
||||
rethrow?: boolean;
|
||||
}
|
||||
|
||||
function useToastOnFail() {
|
||||
return React.useCallback(
|
||||
(action: string, { rethrow = false }: ToastOnFailOptions = {}) =>
|
||||
(error: any) => {
|
||||
const err = error as Error;
|
||||
toast({
|
||||
title: `Unable to ${action}`,
|
||||
description: err.message ?? "Something went wrong",
|
||||
variant: "destructive",
|
||||
duration: 10000,
|
||||
});
|
||||
if (rethrow) {
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
export { toast, useToast, useToastOnFail };
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { ClockIcon, Loader2 } from "lucide-react";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { humanizeCronExpression } from "@/lib/cron-expression-utils";
|
||||
import {
|
||||
Select,
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Label } from "@/components/ui/label";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Clipboard } from "lucide-react";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
|
||||
export type BlockOutput = {
|
||||
metadata: {
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||
import * as ToastPrimitives from "@radix-ui/react-toast";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const ToastProvider = ToastPrimitives.Provider;
|
||||
|
||||
const ToastViewport = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Viewport>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Viewport
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
|
||||
|
||||
const toastVariants = cva(
|
||||
"whitespace-pre-line group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border border-neutral-200 p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full dark:border-neutral-800",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border bg-white text-neutral-950 dark:bg-neutral-950 dark:text-neutral-50",
|
||||
destructive:
|
||||
"destructive group border-red-500 bg-red-500 text-neutral-50 dark:border-red-900 dark:bg-red-900 dark:text-neutral-50",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const Toast = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
|
||||
VariantProps<typeof toastVariants>
|
||||
>(({ className, variant, ...props }, ref) => {
|
||||
return (
|
||||
<ToastPrimitives.Root
|
||||
ref={ref}
|
||||
className={cn(toastVariants({ variant }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
Toast.displayName = ToastPrimitives.Root.displayName;
|
||||
|
||||
const ToastAction = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Action>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Action
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border border-neutral-200 bg-transparent px-3 text-sm font-medium transition-colors hover:bg-neutral-100 focus:outline-none focus:ring-1 focus:ring-neutral-950 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-neutral-100/40 group-[.destructive]:hover:border-red-500/30 group-[.destructive]:hover:bg-red-500 group-[.destructive]:hover:text-neutral-50 group-[.destructive]:focus:ring-red-500 dark:border-neutral-800 dark:hover:bg-neutral-800 dark:focus:ring-neutral-300 dark:group-[.destructive]:border-neutral-800/40 dark:group-[.destructive]:hover:border-red-900/30 dark:group-[.destructive]:hover:bg-red-900 dark:group-[.destructive]:hover:text-neutral-50 dark:group-[.destructive]:focus:ring-red-900",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
ToastAction.displayName = ToastPrimitives.Action.displayName;
|
||||
|
||||
const ToastClose = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Close>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Close
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"absolute right-1 top-1 rounded-md p-1 text-neutral-950/50 opacity-0 transition-opacity hover:text-neutral-950 focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600 dark:text-neutral-50/50 dark:hover:text-neutral-50",
|
||||
className,
|
||||
)}
|
||||
toast-close=""
|
||||
{...props}
|
||||
>
|
||||
<Cross2Icon className="h-4 w-4" />
|
||||
</ToastPrimitives.Close>
|
||||
));
|
||||
ToastClose.displayName = ToastPrimitives.Close.displayName;
|
||||
|
||||
const ToastTitle = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Title
|
||||
ref={ref}
|
||||
className={cn("text-sm font-semibold [&+div]:text-xs", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
ToastTitle.displayName = ToastPrimitives.Title.displayName;
|
||||
|
||||
const ToastDescription = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm opacity-90", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
ToastDescription.displayName = ToastPrimitives.Description.displayName;
|
||||
|
||||
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
|
||||
|
||||
type ToastActionElement = React.ReactElement<typeof ToastAction>;
|
||||
|
||||
export {
|
||||
type ToastProps,
|
||||
type ToastActionElement,
|
||||
ToastProvider,
|
||||
ToastViewport,
|
||||
Toast,
|
||||
ToastTitle,
|
||||
ToastDescription,
|
||||
ToastClose,
|
||||
ToastAction,
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Toast,
|
||||
ToastClose,
|
||||
ToastDescription,
|
||||
ToastProvider,
|
||||
ToastTitle,
|
||||
ToastViewport,
|
||||
} from "@/components/ui/toast";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
|
||||
export function Toaster() {
|
||||
const { toasts } = useToast();
|
||||
|
||||
// This neat little feature makes the toaster buggy due to the following issue:
|
||||
// https://github.com/radix-ui/primitives/issues/2233
|
||||
// TODO: Re-enable when the above issue is fixed:
|
||||
// const swipeThreshold = toasts.some((toast) => toast.dismissable === false)
|
||||
// ? Infinity
|
||||
// : undefined;
|
||||
const swipeThreshold = undefined;
|
||||
|
||||
return (
|
||||
<ToastProvider swipeThreshold={swipeThreshold}>
|
||||
{toasts.map(
|
||||
({ id, title, description, action, dismissable, ...props }) => (
|
||||
<Toast key={id} {...props}>
|
||||
<div className="grid gap-1">
|
||||
{title && <ToastTitle>{title}</ToastTitle>}
|
||||
{description && (
|
||||
<ToastDescription>{description}</ToastDescription>
|
||||
)}
|
||||
</div>
|
||||
{action}
|
||||
{dismissable !== false && <ToastClose />}
|
||||
</Toast>
|
||||
),
|
||||
)}
|
||||
<ToastViewport />
|
||||
</ToastProvider>
|
||||
);
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
"use client";
|
||||
|
||||
// Inspired by react-hot-toast library
|
||||
import * as React from "react";
|
||||
|
||||
import type { ToastActionElement, ToastProps } from "@/components/ui/toast";
|
||||
|
||||
const TOAST_LIMIT = 1;
|
||||
const TOAST_REMOVE_DELAY = 1000000;
|
||||
|
||||
type ToasterToast = ToastProps & {
|
||||
id: string;
|
||||
title?: React.ReactNode;
|
||||
description?: React.ReactNode;
|
||||
action?: ToastActionElement;
|
||||
dismissable?: boolean;
|
||||
};
|
||||
|
||||
type ActionTypes = {
|
||||
ADD_TOAST: "ADD_TOAST";
|
||||
UPDATE_TOAST: "UPDATE_TOAST";
|
||||
DISMISS_TOAST: "DISMISS_TOAST";
|
||||
REMOVE_TOAST: "REMOVE_TOAST";
|
||||
};
|
||||
|
||||
let count = 0;
|
||||
|
||||
function genId() {
|
||||
count = (count + 1) % Number.MAX_SAFE_INTEGER;
|
||||
return count.toString();
|
||||
}
|
||||
|
||||
type ActionType = ActionTypes;
|
||||
|
||||
type Action =
|
||||
| {
|
||||
type: ActionType["ADD_TOAST"];
|
||||
toast: ToasterToast;
|
||||
}
|
||||
| {
|
||||
type: ActionType["UPDATE_TOAST"];
|
||||
toast: Partial<ToasterToast>;
|
||||
}
|
||||
| {
|
||||
type: ActionType["DISMISS_TOAST"];
|
||||
toastId?: ToasterToast["id"];
|
||||
}
|
||||
| {
|
||||
type: ActionType["REMOVE_TOAST"];
|
||||
toastId?: ToasterToast["id"];
|
||||
};
|
||||
|
||||
interface State {
|
||||
toasts: ToasterToast[];
|
||||
}
|
||||
|
||||
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
|
||||
|
||||
const addToRemoveQueue = (toastId: string) => {
|
||||
if (toastTimeouts.has(toastId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
toastTimeouts.delete(toastId);
|
||||
dispatch({
|
||||
type: "REMOVE_TOAST",
|
||||
toastId: toastId,
|
||||
});
|
||||
}, TOAST_REMOVE_DELAY);
|
||||
|
||||
toastTimeouts.set(toastId, timeout);
|
||||
};
|
||||
|
||||
export const reducer = (state: State, action: Action): State => {
|
||||
switch (action.type) {
|
||||
case "ADD_TOAST":
|
||||
return {
|
||||
...state,
|
||||
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
|
||||
};
|
||||
|
||||
case "UPDATE_TOAST":
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === action.toast.id ? { ...t, ...action.toast } : t,
|
||||
),
|
||||
};
|
||||
|
||||
case "DISMISS_TOAST": {
|
||||
const { toastId } = action;
|
||||
|
||||
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
||||
// but I'll keep it here for simplicity
|
||||
if (toastId) {
|
||||
addToRemoveQueue(toastId);
|
||||
} else {
|
||||
state.toasts.forEach((toast) => {
|
||||
addToRemoveQueue(toast.id);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === toastId || toastId === undefined
|
||||
? {
|
||||
...t,
|
||||
open: false,
|
||||
}
|
||||
: t,
|
||||
),
|
||||
};
|
||||
}
|
||||
case "REMOVE_TOAST":
|
||||
if (action.toastId === undefined) {
|
||||
return {
|
||||
...state,
|
||||
toasts: [],
|
||||
};
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.filter((t) => t.id !== action.toastId),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const listeners: Array<(state: State) => void> = [];
|
||||
|
||||
let memoryState: State = { toasts: [] };
|
||||
|
||||
function dispatch(action: Action) {
|
||||
memoryState = reducer(memoryState, action);
|
||||
listeners.forEach((listener) => {
|
||||
listener(memoryState);
|
||||
});
|
||||
}
|
||||
|
||||
type Toast = Omit<ToasterToast, "id">;
|
||||
|
||||
function toast({ ...props }: Toast) {
|
||||
const id = genId();
|
||||
|
||||
const update = (props: ToasterToast) =>
|
||||
dispatch({
|
||||
type: "UPDATE_TOAST",
|
||||
toast: { ...props, id },
|
||||
});
|
||||
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
|
||||
|
||||
dispatch({
|
||||
type: "ADD_TOAST",
|
||||
toast: {
|
||||
...props,
|
||||
id,
|
||||
open: true,
|
||||
onOpenChange: (open) => {
|
||||
if (!open) dismiss();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
id: id,
|
||||
dismiss,
|
||||
update,
|
||||
};
|
||||
}
|
||||
|
||||
function useToast() {
|
||||
const [state, setState] = React.useState<State>(memoryState);
|
||||
|
||||
React.useEffect(() => {
|
||||
listeners.push(setState);
|
||||
return () => {
|
||||
const index = listeners.indexOf(setState);
|
||||
if (index > -1) {
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
};
|
||||
}, [state]);
|
||||
|
||||
return {
|
||||
...state,
|
||||
toast,
|
||||
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
|
||||
};
|
||||
}
|
||||
|
||||
interface ToastOnFailOptions {
|
||||
rethrow?: boolean;
|
||||
}
|
||||
|
||||
function useToastOnFail() {
|
||||
return React.useCallback(
|
||||
(action: string, { rethrow = false }: ToastOnFailOptions = {}) =>
|
||||
(error: any) => {
|
||||
const err = error as Error;
|
||||
toast({
|
||||
title: `Unable to ${action}`,
|
||||
description: err.message ?? "Something went wrong",
|
||||
variant: "destructive",
|
||||
duration: 10000,
|
||||
});
|
||||
if (rethrow) {
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
export { toast, useToast, useToastOnFail };
|
||||
@@ -2,7 +2,7 @@ import { CustomEdge } from "@/components/CustomEdge";
|
||||
import { CustomNode } from "@/components/CustomNode";
|
||||
import { useOnboarding } from "@/components/onboarding/onboarding-provider";
|
||||
import { InputItem } from "@/components/RunnerUIWrapper";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import BackendAPI, {
|
||||
Block,
|
||||
BlockIOSubSchema,
|
||||
|
||||
Reference in New Issue
Block a user