Workflow editor (#735)

Co-authored-by: Muhammed Salih Altun <muhammedsalihaltun@gmail.com>
This commit is contained in:
Kerem Yilmaz
2024-08-26 21:31:42 +03:00
committed by GitHub
parent d21b6e6adc
commit 3502093200
48 changed files with 2803 additions and 193 deletions

View File

@@ -0,0 +1,38 @@
import { useLayoutEffect, useRef } from "react";
import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/util/utils";
type Props = React.ComponentProps<typeof Textarea>;
function AutoResizingTextarea(props: Props) {
const ref = useRef<HTMLTextAreaElement>(null);
useLayoutEffect(() => {
// size the textarea correctly on first render
if (!ref.current) {
return;
}
ref.current.style.height = `${ref.current.scrollHeight + 2}px`;
}, []);
function setSize() {
if (!ref.current) {
return;
}
ref.current.style.height = "auto";
ref.current.style.height = `${ref.current.scrollHeight + 2}px`;
}
return (
<Textarea
{...props}
onKeyDown={setSize}
onInput={setSize}
ref={ref}
rows={1}
className={cn("min-h-0 resize-none overflow-y-hidden", props.className)}
/>
);
}
export { AutoResizingTextarea };

View File

@@ -8,6 +8,7 @@ import { Button } from "./ui/button";
import { Input } from "./ui/input";
import { Label } from "./ui/label";
import { toast } from "./ui/use-toast";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./ui/tabs";
export type FileInputValue =
| {
@@ -36,8 +37,6 @@ function showFileSizeError() {
function FileUpload({ value, onChange }: Props) {
const credentialGetter = useCredentialGetter();
const [file, setFile] = useState<File | null>(null);
const [fileUrl, setFileUrl] = useState<string>("");
const [highlight, setHighlight] = useState(false);
const inputId = useId();
const uploadFileMutation = useMutation({
@@ -92,37 +91,44 @@ function FileUpload({ value, onChange }: Props) {
onChange(null);
}
if (value === null) {
return (
<div className="flex gap-4">
<div className="w-1/2">
const isManualUpload =
typeof value === "object" && value !== null && file && "s3uri" in value;
return (
<Tabs
className="h-36 w-full"
defaultValue="upload"
value={value === null ? undefined : isManualUpload ? "upload" : "fileURL"}
onValueChange={(value) => {
if (value === "upload") {
onChange(null);
} else {
onChange("");
}
}}
>
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="upload">Upload</TabsTrigger>
<TabsTrigger value="fileURL">File URL</TabsTrigger>
</TabsList>
<TabsContent value="upload">
{isManualUpload && ( // redundant check for ts compiler
<div className="flex h-full items-center gap-4">
<a href={value.presignedUrl} className="underline">
<span>{file.name}</span>
</a>
<Button onClick={() => reset()}>Change</Button>
</div>
)}
{value === null && (
<Label
htmlFor={inputId}
className={cn(
"flex w-full cursor-pointer items-center justify-center border border-dashed py-8",
{
"border-slate-500": highlight,
},
"flex w-full cursor-pointer items-center justify-center border border-dashed py-8 hover:border-slate-500",
)}
onDragEnter={(event) => {
event.preventDefault();
event.stopPropagation();
setHighlight(true);
}}
onDragOver={(event) => {
event.preventDefault();
event.stopPropagation();
setHighlight(true);
}}
onDragLeave={(event) => {
event.preventDefault();
event.stopPropagation();
setHighlight(false);
}}
onDrop={(event) => {
event.preventDefault();
event.stopPropagation();
setHighlight(false);
if (
event.dataTransfer.files &&
event.dataTransfer.files.length > 0
@@ -155,49 +161,21 @@ function FileUpload({ value, onChange }: Props) {
</span>
</div>
</Label>
</div>
<div className="flex flex-col items-center justify-center before:flex before:bg-slate-600 before:content-['']">
OR
</div>
<div className="w-1/2">
)}
</TabsContent>
<TabsContent value="fileURL">
<div className="space-y-2">
<Label>File URL</Label>
<div className="flex gap-2">
{typeof value === "string" && (
<Input
value={fileUrl}
onChange={(e) => setFileUrl(e.target.value)}
value={value}
onChange={(event) => onChange(event.target.value)}
/>
<Button
onClick={() => {
onChange(fileUrl);
}}
>
Save
</Button>
</div>
)}
</div>
</div>
);
}
if (typeof value === "string") {
return (
<div className="flex items-center gap-4">
<span>{value}</span>
<Button onClick={() => reset()}>Change</Button>
</div>
);
}
if (typeof value === "object" && file && "s3uri" in value) {
return (
<div className="flex items-center gap-4">
<a href={value.presignedUrl} className="underline">
<span>{file.name}</span>
</a>
<Button onClick={() => reset()}>Change</Button>
</div>
);
}
</TabsContent>
</Tabs>
);
}
export { FileUpload };

View File

@@ -0,0 +1,27 @@
import * as React from "react";
import * as SwitchPrimitives from "@radix-ui/react-switch";
import { cn } from "@/util/utils";
const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className,
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0",
)}
/>
</SwitchPrimitives.Root>
));
Switch.displayName = SwitchPrimitives.Root.displayName;
export { Switch };