Skip to content

Commit

Permalink
Make scrollable areas more consistent (#952)
Browse files Browse the repository at this point in the history
Co-authored-by: wintonzheng <null>
  • Loading branch information
wintonzheng authored Oct 10, 2024
1 parent 3977684 commit 267adea
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 124 deletions.
19 changes: 15 additions & 4 deletions skyvern-frontend/src/components/ui/scroll-area.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,26 @@ const ScrollArea = React.forwardRef<
className={cn("relative overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
{children}
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
));
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<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
Expand All @@ -43,4 +54,4 @@ const ScrollBar = React.forwardRef<
));
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;

export { ScrollArea, ScrollBar };
export { ScrollArea, ScrollBar, ScrollAreaViewport };
38 changes: 22 additions & 16 deletions skyvern-frontend/src/routes/tasks/create/PromptBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import { AxiosError } from "axios";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
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(
values: TaskGenerationApiResponse,
Expand Down Expand Up @@ -178,21 +182,23 @@ function PromptBox() {
</div>
</div>
<ScrollArea>
<div className="flex gap-4 rounded-sm bg-slate-elevation1 p-4">
{examplePrompts.map((examplePrompt) => {
return (
<div
key={examplePrompt}
className="cursor-pointer whitespace-nowrap rounded-sm bg-slate-elevation3 px-4 py-3 hover:bg-slate-elevation5"
onClick={() => {
setPrompt(examplePrompt);
}}
>
{examplePrompt}
</div>
);
})}
</div>
<ScrollAreaViewport className="h-full w-full rounded-[inherit]">
<div className="flex gap-4 rounded-sm bg-slate-elevation1 p-4">
{examplePrompts.map((examplePrompt) => {
return (
<div
key={examplePrompt}
className="cursor-pointer whitespace-nowrap rounded-sm bg-slate-elevation3 px-4 py-3 hover:bg-slate-elevation5"
onClick={() => {
setPrompt(examplePrompt);
}}
>
{examplePrompt}
</div>
);
})}
</div>
</ScrollAreaViewport>
<ScrollBar orientation="horizontal" />
</ScrollArea>
</div>
Expand Down
47 changes: 26 additions & 21 deletions skyvern-frontend/src/routes/tasks/detail/ScrollableActionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getClient } from "@/api/AxiosClient";
import { Action, ActionTypes, ReadableActionTypes } from "@/api/types";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import {
Tooltip,
Expand Down Expand Up @@ -155,29 +156,33 @@ function ScrollableActionList({
<ArrowDownIcon />
</Button>
</div>
<div className="w-full space-y-4 overflow-y-scroll px-4 pb-4">
{showStreamOption && (
<div
key="stream"
ref={(element) => {
refs.current[data.length] = element;
}}
className={cn(
"flex cursor-pointer rounded-lg border p-4 shadow-md hover:border-slate-300",
{
"border-slate-300": activeIndex === "stream",
},
<ScrollArea>
<ScrollAreaViewport className="h-full w-full rounded-[inherit]">
<div className="w-full space-y-4 px-4 pb-4">
{showStreamOption && (
<div
key="stream"
ref={(element) => {
refs.current[data.length] = element;
}}
className={cn(
"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")}
>
<div className="flex items-center gap-2 text-lg">
<DotFilledIcon className="h-6 w-6 text-red-500" />
Live
</div>
{getReverseActions()}
</div>
)}
{getReverseActions()}
</div>
</ScrollAreaViewport>
</ScrollArea>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from "@/components/ui/dropdown-menu";
import { useReactFlow } from "@xyflow/react";
import { useWorkflowHasChangesStore } from "@/store/WorkflowHasChangesStore";
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";

const WORKFLOW_EDIT_PANEL_WIDTH = 20 * 16;
const WORKFLOW_EDIT_PANEL_GAP = 1 * 16;
Expand Down Expand Up @@ -105,89 +106,96 @@ function WorkflowParametersPanel() {
</DropdownMenuContent>
</DropdownMenu>

<section className="max-h-[600px] space-y-2 overflow-y-scroll">
{workflowParameters.map((parameter) => {
return (
<div
key={parameter.key}
className="flex items-center justify-between rounded-md bg-slate-elevation1 px-3 py-2"
>
<div className="flex items-center gap-4">
<span className="text-sm">{parameter.key}</span>
{parameter.parameterType === "workflow" ? (
<span className="text-sm text-slate-400">
{parameter.dataType}
</span>
) : (
<span className="text-sm text-slate-400">
{parameter.parameterType}
</span>
)}
</div>
<div className="flex items-center gap-2">
<MixerVerticalIcon
className="cursor-pointer"
onClick={() => {
setOperationPanelState({
active: true,
operation: "edit",
parameter: parameter,
type: parameter.parameterType,
});
}}
/>
<Dialog>
<DialogTrigger>
<GarbageIcon className="size-4 cursor-pointer text-destructive-foreground text-red-600" />
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
This parameter will be deleted.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Cancel</Button>
</DialogClose>
<Button
variant="destructive"
onClick={() => {
setWorkflowParameters(
workflowParameters.filter(
(p) => p.key !== parameter.key,
),
);
setHasChanges(true);
setNodes((nodes) => {
return nodes.map((node) => {
if (node.type === "task") {
return {
...node,
data: {
...node.data,
parameterKeys: (
node.data.parameterKeys as Array<string>
).filter((key) => key !== parameter.key),
},
};
}
return node;
});
});
}}
>
Delete
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
</div>
);
})}
</section>
<ScrollArea>
<ScrollAreaViewport className="max-h-[600px]">
<section className="space-y-2">
{workflowParameters.map((parameter) => {
return (
<div
key={parameter.key}
className="flex items-center justify-between rounded-md bg-slate-elevation1 px-3 py-2"
>
<div className="flex items-center gap-4">
<span className="text-sm">{parameter.key}</span>
{parameter.parameterType === "workflow" ? (
<span className="text-sm text-slate-400">
{parameter.dataType}
</span>
) : (
<span className="text-sm text-slate-400">
{parameter.parameterType}
</span>
)}
</div>
<div className="flex items-center gap-2">
<MixerVerticalIcon
className="cursor-pointer"
onClick={() => {
setOperationPanelState({
active: true,
operation: "edit",
parameter: parameter,
type: parameter.parameterType,
});
}}
/>
<Dialog>
<DialogTrigger>
<GarbageIcon className="size-4 cursor-pointer text-destructive-foreground text-red-600" />
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
This parameter will be deleted.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Cancel</Button>
</DialogClose>
<Button
variant="destructive"
onClick={() => {
setWorkflowParameters(
workflowParameters.filter(
(p) => p.key !== parameter.key,
),
);
setHasChanges(true);
setNodes((nodes) => {
return nodes.map((node) => {
if (node.type === "task") {
return {
...node,
data: {
...node.data,
parameterKeys: (
node.data
.parameterKeys as Array<string>
).filter(
(key) => key !== parameter.key,
),
},
};
}
return node;
});
});
}}
>
Delete
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
</div>
);
})}
</section>
</ScrollAreaViewport>
</ScrollArea>
</div>
{operationPanelState.active && (
<div
Expand Down

0 comments on commit 267adea

Please sign in to comment.