diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 2b57362..be0042a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -7,6 +7,7 @@ import { siteConfig } from "@/config/site"; import { ThemeProvider } from "@/components/theme-provider"; import { TailwindIndicator } from "@/components/tailwind-indicator"; import Header from "@/components/header"; +import { Toaster } from "@/components/ui/toaster"; export const metadata: Metadata = { title: { @@ -61,6 +62,7 @@ export default function RootLayout({ children }: RootLayoutProps) { + diff --git a/src/components/form/download-button.tsx b/src/components/form/download-button.tsx deleted file mode 100644 index daad9d8..0000000 --- a/src/components/form/download-button.tsx +++ /dev/null @@ -1,53 +0,0 @@ -"use client"; - -import { useRef } from "react"; - -import { stringify } from "yaml"; -import { - getSubmitButtonOptions, - RJSFSchema, - SubmitButtonProps, -} from "@rjsf/utils"; - -import { Button } from "@/components/ui/button"; - -export function DownloadButton( - props: SubmitButtonProps, - formData: any, - formStatus: any, -) { - console.log(props); - const { uiSchema } = props; - const { norender } = getSubmitButtonOptions(uiSchema); - if (norender) { - return null; - } - const linkRef = useRef(null); - const handleDownload = async () => { - const yaml_out = stringify(formData.formData).trimEnd(); - const blob = new Blob([yaml_out], { - type: "application/yaml", - }); - const url = window.URL.createObjectURL(blob); - const link = linkRef.current as HTMLAnchorElement | null; - - if (!link) { - return; - } - - link.href = url; - link.download = "cluster.yaml"; - link.click(); - window.URL.revokeObjectURL(url); - }; - - return ( - <> - - - - - ); -} diff --git a/src/components/form/fields.tsx b/src/components/form/fields.tsx deleted file mode 100644 index 98a0091..0000000 --- a/src/components/form/fields.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { - RJSFSchema, - UiSchema, - FieldProps, - RegistryFieldsType, -} from "@rjsf/utils"; -import React from "react"; - -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, - SelectGroup, - SelectLabel, -} from "@/components/ui/select"; - -export default class version extends React.Component { - constructor(props: FieldProps) { - super(props); - this.state = { ...props.formData }; - } - - onChange(name: string) { - return (event: any) => { - this.setState( - { - [name]: "v" + event, - }, - () => this.props.onChange(this.state), - ); - }; - } - - render() { - const k8s_versions = { - "1.31": ["1.31.1", "1.31.0"], - "1.30": ["1.30.5", "1.30.4", "1.30.3", "1.30.2", "1.30.1", "1.30.0"], - "1.29": [ - "1.29.9", - "1.29.8", - "1.29.7", - "1.29.6", - "1.29.5", - "1.29.4", - "1.29.3", - "1.29.2", - "1.29.1", - "1.29.0", - ], - "1.28": [ - "1.28.14", - "1.28.13", - "1.28.12", - "1.28.11", - "1.28.10", - "1.28.9", - "1.28.8", - "1.28.7", - "1.28.6", - "1.28.5", - "1.28.4", - "1.28.3", - "1.28.2", - "1.28.1", - "1.28.0", - ], - }; - - return ( - <> - - -

- Select which Kubernetes minor version you want -

- - ); - } -} diff --git a/src/components/form/form.tsx b/src/components/form/form.tsx index a131322..a622e11 100644 --- a/src/components/form/form.tsx +++ b/src/components/form/form.tsx @@ -1,37 +1,31 @@ "use client"; -import { useState, createRef } from "react"; +import { useState } from "react"; import React from "react"; import validator from "@rjsf/validator-ajv8"; -import { getDefaultRegistry } from "@rjsf/core"; -import { ObjectFieldTemplateProps } from "@rjsf/utils"; +import { RJSFValidationError } from "@rjsf/utils"; import { stringify } from "yaml"; import SyntaxHighlighter from "react-syntax-highlighter"; import { convertYamlFormat } from "@/lib/utils"; import uiSchema from "@/components/form/uischema"; import SubmitButton from "@/components/form/custom/SubmitButton/SubmitButton"; -import { Separator } from "@/components/ui/separator"; import { Card, CardContent, - CardDescription, - CardFooter, CardHeader, CardTitle, } from "@/components/ui/card"; import { widgets } from "@/components/form/widgets"; import { Form as RJSForm } from "@/components/form/custom"; -import { DownloadButton } from "@/components/form/download-button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, - SelectGroup, - SelectLabel, } from "@/components/ui/select"; +import { useToast } from "@/lib/use-toast"; export const ClusterForm = (schemas: any) => { const schema = schemas?.schemas; @@ -50,6 +44,18 @@ export const ClusterForm = (schemas: any) => { .slice(0, 1)[0] .trimEnd(); + const focusOnError = (error: RJSFValidationError) => { + setTimeout(() => { + window.scroll({ + top: 0, + left: 0, + behavior: "smooth", + }); + }, 0); + }; + + const { toast } = useToast(); + const onSubmit = (data: any, e: React.FormEvent) => { const yamlData = JSON.parse(JSON.stringify(data.formData)); const clusterName = yamlData.metadata?.name || "cluster"; @@ -62,6 +68,10 @@ export const ClusterForm = (schemas: any) => { link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); + + toast({ + title: `🎉 Downloading ${clusterName}.yaml`, + }); }; return ( @@ -112,6 +122,7 @@ export const ClusterForm = (schemas: any) => { formData={formData} onChange={(e: any) => setFormData(e.formData)} onSubmit={onSubmit} + focusOnFirstError={focusOnError} templates={{ ButtonTemplates: { SubmitButton } }} > diff --git a/src/components/ui/toast.tsx b/src/components/ui/toast.tsx index 0b671b7..443aedb 100644 --- a/src/components/ui/toast.tsx +++ b/src/components/ui/toast.tsx @@ -25,7 +25,7 @@ const ToastViewport = React.forwardRef< ToastViewport.displayName = ToastPrimitives.Viewport.displayName; const toastVariants = cva( - "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 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", + "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-lg border p-6 pr-8 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", { variants: { variant: { @@ -62,7 +62,7 @@ const ToastAction = React.forwardRef<