Make scrollable areas more consistent (#952)
Co-authored-by: wintonzheng <null>
This commit is contained in:
@@ -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 };
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user