Make scrollable areas more consistent (#952)

Co-authored-by: wintonzheng <null>
This commit is contained in:
Shuchang Zheng
2024-10-10 06:59:03 -07:00
committed by GitHub
parent 39776842f3
commit 267adea411
4 changed files with 154 additions and 124 deletions

View File

@@ -12,15 +12,26 @@ const ScrollArea = React.forwardRef<
className={cn("relative overflow-hidden", className)} className={cn("relative overflow-hidden", className)}
{...props} {...props}
> >
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]"> {children}
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar /> <ScrollBar />
<ScrollAreaPrimitive.Corner /> <ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root> </ScrollAreaPrimitive.Root>
)); ));
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
const ScrollAreaViewport = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaViewport>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaViewport>
>(({ children, ...props }, ref) => {
return (
<ScrollAreaPrimitive.Viewport ref={ref} {...props}>
{children}
</ScrollAreaPrimitive.Viewport>
);
});
ScrollAreaViewport.displayName =
ScrollAreaPrimitive.ScrollAreaViewport.displayName;
const ScrollBar = React.forwardRef< const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>, React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar> React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
@@ -43,4 +54,4 @@ const ScrollBar = React.forwardRef<
)); ));
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
export { ScrollArea, ScrollBar }; export { ScrollArea, ScrollBar, ScrollAreaViewport };

View File

@@ -10,7 +10,11 @@ import { AxiosError } from "axios";
import { useState } from "react"; import { useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { stringify as convertToYAML } from "yaml"; import { stringify as convertToYAML } from "yaml";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; import {
ScrollArea,
ScrollAreaViewport,
ScrollBar,
} from "@/components/ui/scroll-area";
function createTaskFromTaskGenerationParameters( function createTaskFromTaskGenerationParameters(
values: TaskGenerationApiResponse, values: TaskGenerationApiResponse,
@@ -178,21 +182,23 @@ function PromptBox() {
</div> </div>
</div> </div>
<ScrollArea> <ScrollArea>
<div className="flex gap-4 rounded-sm bg-slate-elevation1 p-4"> <ScrollAreaViewport className="h-full w-full rounded-[inherit]">
{examplePrompts.map((examplePrompt) => { <div className="flex gap-4 rounded-sm bg-slate-elevation1 p-4">
return ( {examplePrompts.map((examplePrompt) => {
<div return (
key={examplePrompt} <div
className="cursor-pointer whitespace-nowrap rounded-sm bg-slate-elevation3 px-4 py-3 hover:bg-slate-elevation5" key={examplePrompt}
onClick={() => { className="cursor-pointer whitespace-nowrap rounded-sm bg-slate-elevation3 px-4 py-3 hover:bg-slate-elevation5"
setPrompt(examplePrompt); onClick={() => {
}} setPrompt(examplePrompt);
> }}
{examplePrompt} >
</div> {examplePrompt}
); </div>
})} );
</div> })}
</div>
</ScrollAreaViewport>
<ScrollBar orientation="horizontal" /> <ScrollBar orientation="horizontal" />
</ScrollArea> </ScrollArea>
</div> </div>

View File

@@ -2,6 +2,7 @@ import { getClient } from "@/api/AxiosClient";
import { Action, ActionTypes, ReadableActionTypes } from "@/api/types"; import { Action, ActionTypes, ReadableActionTypes } from "@/api/types";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { import {
Tooltip, Tooltip,
@@ -155,29 +156,33 @@ function ScrollableActionList({
<ArrowDownIcon /> <ArrowDownIcon />
</Button> </Button>
</div> </div>
<div className="w-full space-y-4 overflow-y-scroll px-4 pb-4"> <ScrollArea>
{showStreamOption && ( <ScrollAreaViewport className="h-full w-full rounded-[inherit]">
<div <div className="w-full space-y-4 px-4 pb-4">
key="stream" {showStreamOption && (
ref={(element) => { <div
refs.current[data.length] = element; key="stream"
}} ref={(element) => {
className={cn( refs.current[data.length] = element;
"flex cursor-pointer rounded-lg border p-4 shadow-md hover:border-slate-300", }}
{ className={cn(
"border-slate-300": activeIndex === "stream", "flex cursor-pointer rounded-lg border p-4 shadow-md hover:border-slate-300",
}, {
"border-slate-300": activeIndex === "stream",
},
)}
onClick={() => onActiveIndexChange("stream")}
>
<div className="flex items-center gap-2 text-lg">
<DotFilledIcon className="h-6 w-6 text-red-500" />
Live
</div>
</div>
)} )}
onClick={() => onActiveIndexChange("stream")} {getReverseActions()}
>
<div className="flex items-center gap-2 text-lg">
<DotFilledIcon className="h-6 w-6 text-red-500" />
Live
</div>
</div> </div>
)} </ScrollAreaViewport>
{getReverseActions()} </ScrollArea>
</div>
</div> </div>
); );
} }

View File

@@ -26,6 +26,7 @@ import {
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { useReactFlow } from "@xyflow/react"; import { useReactFlow } from "@xyflow/react";
import { useWorkflowHasChangesStore } from "@/store/WorkflowHasChangesStore"; import { useWorkflowHasChangesStore } from "@/store/WorkflowHasChangesStore";
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
const WORKFLOW_EDIT_PANEL_WIDTH = 20 * 16; const WORKFLOW_EDIT_PANEL_WIDTH = 20 * 16;
const WORKFLOW_EDIT_PANEL_GAP = 1 * 16; const WORKFLOW_EDIT_PANEL_GAP = 1 * 16;
@@ -105,89 +106,96 @@ function WorkflowParametersPanel() {
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
<section className="max-h-[600px] space-y-2 overflow-y-scroll"> <ScrollArea>
{workflowParameters.map((parameter) => { <ScrollAreaViewport className="max-h-[600px]">
return ( <section className="space-y-2">
<div {workflowParameters.map((parameter) => {
key={parameter.key} return (
className="flex items-center justify-between rounded-md bg-slate-elevation1 px-3 py-2" <div
> key={parameter.key}
<div className="flex items-center gap-4"> className="flex items-center justify-between rounded-md bg-slate-elevation1 px-3 py-2"
<span className="text-sm">{parameter.key}</span> >
{parameter.parameterType === "workflow" ? ( <div className="flex items-center gap-4">
<span className="text-sm text-slate-400"> <span className="text-sm">{parameter.key}</span>
{parameter.dataType} {parameter.parameterType === "workflow" ? (
</span> <span className="text-sm text-slate-400">
) : ( {parameter.dataType}
<span className="text-sm text-slate-400"> </span>
{parameter.parameterType} ) : (
</span> <span className="text-sm text-slate-400">
)} {parameter.parameterType}
</div> </span>
<div className="flex items-center gap-2"> )}
<MixerVerticalIcon </div>
className="cursor-pointer" <div className="flex items-center gap-2">
onClick={() => { <MixerVerticalIcon
setOperationPanelState({ className="cursor-pointer"
active: true, onClick={() => {
operation: "edit", setOperationPanelState({
parameter: parameter, active: true,
type: parameter.parameterType, operation: "edit",
}); parameter: parameter,
}} type: parameter.parameterType,
/> });
<Dialog> }}
<DialogTrigger> />
<GarbageIcon className="size-4 cursor-pointer text-destructive-foreground text-red-600" /> <Dialog>
</DialogTrigger> <DialogTrigger>
<DialogContent> <GarbageIcon className="size-4 cursor-pointer text-destructive-foreground text-red-600" />
<DialogHeader> </DialogTrigger>
<DialogTitle>Are you sure?</DialogTitle> <DialogContent>
<DialogDescription> <DialogHeader>
This parameter will be deleted. <DialogTitle>Are you sure?</DialogTitle>
</DialogDescription> <DialogDescription>
</DialogHeader> This parameter will be deleted.
<DialogFooter> </DialogDescription>
<DialogClose asChild> </DialogHeader>
<Button variant="secondary">Cancel</Button> <DialogFooter>
</DialogClose> <DialogClose asChild>
<Button <Button variant="secondary">Cancel</Button>
variant="destructive" </DialogClose>
onClick={() => { <Button
setWorkflowParameters( variant="destructive"
workflowParameters.filter( onClick={() => {
(p) => p.key !== parameter.key, setWorkflowParameters(
), workflowParameters.filter(
); (p) => p.key !== parameter.key,
setHasChanges(true); ),
setNodes((nodes) => { );
return nodes.map((node) => { setHasChanges(true);
if (node.type === "task") { setNodes((nodes) => {
return { return nodes.map((node) => {
...node, if (node.type === "task") {
data: { return {
...node.data, ...node,
parameterKeys: ( data: {
node.data.parameterKeys as Array<string> ...node.data,
).filter((key) => key !== parameter.key), parameterKeys: (
}, node.data
}; .parameterKeys as Array<string>
} ).filter(
return node; (key) => key !== parameter.key,
}); ),
}); },
}} };
> }
Delete return node;
</Button> });
</DialogFooter> });
</DialogContent> }}
</Dialog> >
</div> Delete
</div> </Button>
); </DialogFooter>
})} </DialogContent>
</section> </Dialog>
</div>
</div>
);
})}
</section>
</ScrollAreaViewport>
</ScrollArea>
</div> </div>
{operationPanelState.active && ( {operationPanelState.active && (
<div <div