fix: improve notes functionality, update theme colors definition and resolve ui and ux small bugs (#4414)
* Fixed background blur overlay color on dialogs * Try to fix f5 error * Fix text color of notes * Fix bg color of nodenode to first one available if not existent * Removed unused imports * Added new node colors * Updated color of placeholder note node * Fixed notes to appear as soon as when the add button is clicked * Added transparent option to notes * Fixed editor design * Fix design of notes editor * Update text color on the note node description * Added canvas dot variable * Added size and gap definition to background dots * Updated emerald colors and badge * used correct badges on tableAutoCellRender * Used correct colors on the component global variable badge * Fix color on light mode * Fixed emerald color on the status of component * Applied static pink to active icons on navs * Make sidebar narrower * Updated size of / * Fixed Beta and Legacy badges * Fixed position of chevron * Fixed node name input * Updated clear search button * Updated color for grid dots * Updated sidebar filter color * Added chat input check * Fixed sorting of flow sidebar component * Fix canvas color * Updated sticky notes test * Fixed tests * Fixed test
This commit is contained in:
parent
e5969b2f18
commit
de7b23ea93
27 changed files with 518 additions and 406 deletions
|
|
@ -1,6 +1,7 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="/" />
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export default function NodeDescription({
|
|||
selected,
|
||||
nodeId,
|
||||
emptyPlaceholder = "Double Click to Edit Description",
|
||||
placeholderClassName,
|
||||
charLimit,
|
||||
inputClassName,
|
||||
mdClassName,
|
||||
|
|
@ -20,6 +21,7 @@ export default function NodeDescription({
|
|||
selected: boolean;
|
||||
nodeId: string;
|
||||
emptyPlaceholder?: string;
|
||||
placeholderClassName?: string;
|
||||
charLimit?: number;
|
||||
inputClassName?: string;
|
||||
mdClassName?: string;
|
||||
|
|
@ -62,7 +64,8 @@ export default function NodeDescription({
|
|||
className={cn(
|
||||
!inputDescription ? "overflow-auto" : "",
|
||||
hasScroll ? "nowheel" : "",
|
||||
charLimit ? "px-2" : "",
|
||||
charLimit ? "px-2 pb-4" : "",
|
||||
"w-full",
|
||||
)}
|
||||
>
|
||||
{inputDescription ? (
|
||||
|
|
@ -114,10 +117,11 @@ export default function NodeDescription({
|
|||
{charLimit && (
|
||||
<div
|
||||
className={cn(
|
||||
"text-left text-[13px]",
|
||||
"pt-1 text-left text-[13px]",
|
||||
(nodeDescription?.length ?? 0) >= charLimit
|
||||
? "text-error"
|
||||
: "text-primary",
|
||||
placeholderClassName,
|
||||
)}
|
||||
data-testid="note_char_limit"
|
||||
>
|
||||
|
|
@ -130,8 +134,9 @@ export default function NodeDescription({
|
|||
data-testid="generic-node-desc"
|
||||
ref={overflowRef}
|
||||
className={cn(
|
||||
"nodoubleclick generic-node-desc-text h-full cursor-text text-[13px] word-break-break-word dark:text-note-placeholder",
|
||||
"nodoubleclick generic-node-desc-text h-full cursor-text text-[13px] word-break-break-word",
|
||||
description === "" || !description ? "font-light italic" : "",
|
||||
placeholderClassName,
|
||||
)}
|
||||
onDoubleClick={(e) => {
|
||||
setInputDescription(true);
|
||||
|
|
@ -144,7 +149,7 @@ export default function NodeDescription({
|
|||
<Markdown
|
||||
linkTarget="_blank"
|
||||
className={cn(
|
||||
"markdown prose flex h-full w-full flex-col text-[13px] leading-5 text-muted-foreground word-break-break-word dark:prose-invert",
|
||||
"markdown prose flex h-full w-full flex-col text-[13px] leading-5 text-foreground word-break-break-word",
|
||||
mdClassName,
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import InputComponent from "@/components/inputComponent";
|
||||
import { BuildStatus } from "@/constants/enums";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import { VertexBuildTypeAPI } from "@/types/api";
|
||||
|
|
@ -39,7 +38,7 @@ export default function NodeName({
|
|||
|
||||
return inputName ? (
|
||||
<div className="m-[1px] w-full">
|
||||
<InputComponent
|
||||
<Input
|
||||
onBlur={() => {
|
||||
setInputName(false);
|
||||
if (nodeName?.trim() !== "") {
|
||||
|
|
@ -60,10 +59,8 @@ export default function NodeName({
|
|||
}}
|
||||
value={nodeName}
|
||||
autoFocus
|
||||
onChange={setNodeName}
|
||||
password={false}
|
||||
blurOnEnter={true}
|
||||
id={`input-title-${display_name}`}
|
||||
onChange={(e) => setNodeName(e.target.value)}
|
||||
data-testid={`input-title-${display_name}`}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
import { useDarkStore } from "@/stores/darkStore";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import { log } from "console";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Handle, Position, useViewport } from "reactflow";
|
||||
import { Handle, Position } from "reactflow";
|
||||
import ShadTooltip from "../../../../components/shadTooltipComponent";
|
||||
import {
|
||||
isValidConnection,
|
||||
scapedJSONStringfy,
|
||||
} from "../../../../utils/reactflowUtils";
|
||||
import { classNames, cn, groupByFamily } from "../../../../utils/utils";
|
||||
import { cn, groupByFamily } from "../../../../utils/utils";
|
||||
import HandleTooltipComponent from "../HandleTooltipComponent";
|
||||
|
||||
export default function HandleRenderComponent({
|
||||
|
|
@ -42,7 +41,7 @@ export default function HandleRenderComponent({
|
|||
nodeId: string;
|
||||
colorName?: string[];
|
||||
}) {
|
||||
const handleColorName = colorName?.[0];
|
||||
const handleColorName = colorName?.[0] ?? "";
|
||||
|
||||
const innerColorName = `inner-${handleColorName}`;
|
||||
const innerForegroundColorName = `${innerColorName}-foreground`;
|
||||
|
|
@ -156,7 +155,7 @@ export default function HandleRenderComponent({
|
|||
source: undefined,
|
||||
sourceHandle: undefined,
|
||||
type: tooltipTitle,
|
||||
color: colors[0],
|
||||
color: handleColorName,
|
||||
}
|
||||
: {
|
||||
sourceHandle: myId,
|
||||
|
|
@ -164,7 +163,7 @@ export default function HandleRenderComponent({
|
|||
target: undefined,
|
||||
targetHandle: undefined,
|
||||
type: tooltipTitle,
|
||||
color: colors[0],
|
||||
color: handleColorName,
|
||||
},
|
||||
[left, myId, nodeId, tooltipTitle, colors],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,15 +5,12 @@ import { usePostValidateComponentCode } from "@/controllers/API/queries/nodes/us
|
|||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import { NodeToolbar, useUpdateNodeInternals } from "reactflow";
|
||||
import IconComponent, {
|
||||
ForwardedIconComponent,
|
||||
} from "../../components/genericIconComponent";
|
||||
import { ForwardedIconComponent } from "../../components/genericIconComponent";
|
||||
import ShadTooltip from "../../components/shadTooltipComponent";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import {
|
||||
TOOLTIP_HIDDEN_OUTPUTS,
|
||||
TOOLTIP_OPEN_HIDDEN_OUTPUTS,
|
||||
TOOLTIP_OUTDATED_NODE,
|
||||
} from "../../constants/constants";
|
||||
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
||||
import useAlertStore from "../../stores/alertStore";
|
||||
|
|
@ -379,6 +376,7 @@ export default function GenericNode({
|
|||
<div>
|
||||
<NodeDescription
|
||||
description={data.node?.description}
|
||||
mdClassName={"dark:prose-invert"}
|
||||
nodeId={data.id}
|
||||
selected={selected}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -17,10 +17,9 @@ import useAlertStore from "@/stores/alertStore";
|
|||
import useFlowStore from "@/stores/flowStore";
|
||||
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||
import { useShortcutsStore } from "@/stores/shortcuts";
|
||||
import { NodeDataType, noteDataType } from "@/types/flow";
|
||||
import { noteDataType } from "@/types/flow";
|
||||
import { classNames, cn, openInNewTab } from "@/utils/utils";
|
||||
import { cloneDeep, set, take } from "lodash";
|
||||
import { useState } from "react";
|
||||
import { cloneDeep } from "lodash";
|
||||
import IconComponent from "../../../components/genericIconComponent";
|
||||
|
||||
export default function NoteToolbarComponent({
|
||||
|
|
@ -30,7 +29,6 @@ export default function NoteToolbarComponent({
|
|||
data: noteDataType;
|
||||
bgColor: string;
|
||||
}) {
|
||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||
const setNoticeData = useAlertStore((state) => state.setNoticeData);
|
||||
const nodes = useFlowStore((state) => state.nodes);
|
||||
const setLastCopiedSelection = useFlowStore(
|
||||
|
|
@ -95,9 +93,12 @@ export default function NoteToolbarComponent({
|
|||
>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: COLOR_OPTIONS[bgColor],
|
||||
backgroundColor: COLOR_OPTIONS[bgColor] ?? "#00000000",
|
||||
}}
|
||||
className="h-4 w-4 rounded-full"
|
||||
className={cn(
|
||||
"h-4 w-4 rounded-full",
|
||||
COLOR_OPTIONS[bgColor] === null && "border",
|
||||
)}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -131,9 +132,10 @@ export default function NoteToolbarComponent({
|
|||
className={cn(
|
||||
"h-4 w-4 rounded-full hover:border hover:border-ring",
|
||||
bgColor === color ? "border-2 border-blue-500" : "",
|
||||
code === null && "border",
|
||||
)}
|
||||
style={{
|
||||
backgroundColor: code,
|
||||
backgroundColor: code ?? "#00000000",
|
||||
}}
|
||||
></div>
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ function NoteNode({
|
|||
selected: boolean;
|
||||
}) {
|
||||
const bgColor =
|
||||
data.node?.template.backgroundColor ?? Object.keys(COLOR_OPTIONS)[0];
|
||||
Object.keys(COLOR_OPTIONS).find(
|
||||
(key) => key === data.node?.template.backgroundColor,
|
||||
) ?? Object.keys(COLOR_OPTIONS)[0];
|
||||
const nodeDiv = useRef<HTMLDivElement>(null);
|
||||
const [size, setSize] = useState({ width: 0, height: 0 });
|
||||
//tricky to start the description with the right size
|
||||
|
|
@ -61,12 +63,13 @@ function NoteNode({
|
|||
maxWidth: NOTE_NODE_MAX_WIDTH,
|
||||
minWidth: NOTE_NODE_MIN_WIDTH,
|
||||
minHeight: NOTE_NODE_MIN_HEIGHT,
|
||||
backgroundColor: COLOR_OPTIONS[bgColor],
|
||||
backgroundColor: COLOR_OPTIONS[bgColor] ?? "#00000000",
|
||||
}}
|
||||
ref={nodeDiv}
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col gap-3 border border-b p-3 transition-all",
|
||||
selected ? "" : "-z-50 shadow-sm",
|
||||
"flex h-full w-full flex-col gap-3 rounded-xl p-3 transition-all",
|
||||
COLOR_OPTIONS[bgColor] !== null &&
|
||||
`border ${!selected && "-z-50 shadow-sm"}`,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
|
|
@ -77,13 +80,26 @@ function NoteNode({
|
|||
}}
|
||||
>
|
||||
<NodeDescription
|
||||
inputClassName="border-0 ring-transparent resize-none rounded-none shadow-none h-full w-full"
|
||||
style={{ backgroundColor: COLOR_OPTIONS[bgColor] }}
|
||||
inputClassName={cn(
|
||||
"border-0 ring-transparent resize-none shadow-none rounded-sm h-full w-full",
|
||||
COLOR_OPTIONS[bgColor] === null
|
||||
? ""
|
||||
: "dark:!ring-background dark:text-background",
|
||||
)}
|
||||
mdClassName={
|
||||
COLOR_OPTIONS[bgColor] === null
|
||||
? "dark:prose-invert"
|
||||
: "dark:!text-background"
|
||||
}
|
||||
style={{ backgroundColor: COLOR_OPTIONS[bgColor] ?? "#00000000" }}
|
||||
charLimit={2500}
|
||||
nodeId={data.id}
|
||||
selected={selected}
|
||||
description={data.node?.description}
|
||||
emptyPlaceholder="Double-click to start typing or enter Markdown..."
|
||||
placeholderClassName={
|
||||
COLOR_OPTIONS[bgColor] === null ? "" : "dark:!text-background"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
import { cn } from "@/utils/utils";
|
||||
import { PopoverAnchor } from "@radix-ui/react-popover";
|
||||
import { X } from "lucide-react";
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
|
||||
const CustomInputPopover = ({
|
||||
id,
|
||||
|
|
@ -97,11 +97,10 @@ const CustomInputPopover = ({
|
|||
))
|
||||
) : selectedOption?.length > 0 ? (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
variant={nodeStyle ? "emerald" : "secondary"}
|
||||
className={cn(
|
||||
"flex items-center gap-1 truncate bg-muted",
|
||||
nodeStyle &&
|
||||
"font-jetbrains rounded-[3px] bg-emerald-100 px-1 text-emerald-700 hover:bg-emerald-200",
|
||||
"flex items-center gap-1 truncate",
|
||||
nodeStyle ? "font-jetbrains rounded-[3px] px-1" : "bg-muted",
|
||||
)}
|
||||
>
|
||||
<div className="max-w-36 truncate">{selectedOption}</div>
|
||||
|
|
|
|||
|
|
@ -40,11 +40,9 @@ export default function TableAutoCellRender({
|
|||
else if (value === "success") {
|
||||
return (
|
||||
<Badge
|
||||
variant="outline"
|
||||
variant="successStatic"
|
||||
size="sq"
|
||||
className={cn(
|
||||
"h-[18px] w-full justify-center bg-success-background text-success-foreground hover:bg-success-background",
|
||||
)}
|
||||
className={cn("h-[18px] w-full justify-center")}
|
||||
>
|
||||
{value}
|
||||
</Badge>
|
||||
|
|
@ -52,11 +50,9 @@ export default function TableAutoCellRender({
|
|||
} else if (value === "failure") {
|
||||
return (
|
||||
<Badge
|
||||
variant="outline"
|
||||
variant="errorStatic"
|
||||
size="sq"
|
||||
className={cn(
|
||||
"h-[18px] w-full justify-center bg-error-background text-error-foreground hover:bg-error-background",
|
||||
)}
|
||||
className={cn("h-[18px] w-full justify-center")}
|
||||
>
|
||||
{value}
|
||||
</Badge>
|
||||
|
|
|
|||
|
|
@ -15,15 +15,20 @@ const badgeVariants = cva(
|
|||
destructive:
|
||||
"bg-destructive hover:bg-destructive/80 border-transparent text-destructive-foreground",
|
||||
outline: "text-primary/80 border-ring/60",
|
||||
secondaryStatic: "bg-input text-muted-foreground border-0",
|
||||
secondaryStatic: "bg-muted text-muted-foreground border-0",
|
||||
pinkStatic: "bg-accent-pink text-accent-pink-foreground border-0",
|
||||
emerald:
|
||||
"bg-accent-emerald text-accent-emerald-foreground hover:bg-accent-emerald-hover",
|
||||
successStatic:
|
||||
"bg-accent-emerald text-accent-emerald-foreground border-0",
|
||||
errorStatic: "bg-error-background text-error-foreground border-0",
|
||||
},
|
||||
size: {
|
||||
sm: "h-4 text-xs",
|
||||
md: "h-5 text-sm",
|
||||
lg: "h-6 text-base",
|
||||
sq: "h-6 px-1.5 text-sm font-medium rounded-md",
|
||||
xq: "h-5 px-1 text-xs font-medium rounded-md",
|
||||
xq: "h-6 px-1.5 text-xs font-medium rounded-sm",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const DialogOverlay = React.forwardRef<
|
|||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"nopan nodelete nodrag noflow fixed inset-0 bottom-0 left-0 right-0 top-0 z-50 overflow-auto bg-blur-shared backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
"nopan nodelete nodrag noflow fixed inset-0 bottom-0 left-0 right-0 top-0 z-50 overflow-auto bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ const DialogOverlay = React.forwardRef<
|
|||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"nopan nodelete nodrag noflow fixed inset-0 bottom-0 left-0 right-0 top-0 z-40 overflow-auto bg-blur-shared backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
"nopan nodelete nodrag noflow fixed inset-0 bottom-0 left-0 right-0 top-0 z-40 overflow-auto bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ const SheetOverlay = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
"fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -871,7 +871,7 @@ export const LOCATIONS_TO_RETURN = ["/flow/", "/settings/"];
|
|||
export const MAX_BATCH_SIZE = 50;
|
||||
|
||||
export const MODAL_CLASSES =
|
||||
"nopan nodelete nodrag noflow fixed inset-0 bottom-0 left-0 right-0 top-0 z-50 overflow-auto bg-blur-shared backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0";
|
||||
"nopan nodelete nodrag noflow fixed inset-0 bottom-0 left-0 right-0 top-0 z-50 overflow-auto bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0";
|
||||
|
||||
export const ALLOWED_IMAGE_INPUT_EXTENSIONS = ["png", "jpg", "jpeg"];
|
||||
|
||||
|
|
@ -926,19 +926,12 @@ export const NOTE_NODE_MAX_HEIGHT = 800;
|
|||
export const NOTE_NODE_MAX_WIDTH = 600;
|
||||
|
||||
export const COLOR_OPTIONS = {
|
||||
default: "var(--note-default)",
|
||||
indigo: "var(--note-indigo)",
|
||||
emerald: "var(--note-emerald)",
|
||||
amber: "var(--note-amber)",
|
||||
red: "var(--note-red)",
|
||||
};
|
||||
|
||||
export const SHADOW_COLOR_OPTIONS = {
|
||||
default: "var(--note-default-opacity)",
|
||||
indigo: "var(--note-indigo-opacity)",
|
||||
emerald: "var(--note-emerald-opacity)",
|
||||
amber: "var(--note-amber-opacity)",
|
||||
red: "var(--note-red-opacity)",
|
||||
amber: "hsl(var(--note-amber))",
|
||||
neutral: "hsl(var(--note-neutral))",
|
||||
rose: "hsl(var(--note-rose))",
|
||||
blue: "hsl(var(--note-blue))",
|
||||
lime: "hsl(var(--note-lime))",
|
||||
transparent: null,
|
||||
};
|
||||
|
||||
export const maxSizeFilesInBytes = 10 * 1024 * 1024; // 10MB in bytes
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export function SaveChangesModal({
|
|||
>
|
||||
<ConfirmationModal.Content>
|
||||
{autoSave ? (
|
||||
<div className="mb-4 flex w-full items-center gap-3 rounded-md bg-gray-100 px-4 py-2 text-gray-800 dark:bg-gray-900/40 dark:text-gray-100">
|
||||
<div className="mb-4 flex w-full items-center gap-3 rounded-md bg-muted px-4 py-2 text-muted-foreground">
|
||||
<Loading className="h-5 w-5" />
|
||||
Saving your changes...
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export function Nav({ categories, currentTab, setCurrentTab }: NavProps) {
|
|||
name={link.icon}
|
||||
className={`h-4 w-4 stroke-2 ${
|
||||
currentTab === link.id
|
||||
? "x-gradient"
|
||||
? "text-accent-pink-foreground"
|
||||
: "text-muted-foreground"
|
||||
}`}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import ForwardedIconComponent from "@/components/genericIconComponent";
|
|||
import LoadingComponent from "@/components/loadingComponent";
|
||||
import { SidebarTrigger, useSidebar } from "@/components/ui/sidebar";
|
||||
import {
|
||||
COLOR_OPTIONS,
|
||||
NOTE_NODE_MIN_HEIGHT,
|
||||
NOTE_NODE_MIN_WIDTH,
|
||||
SHADOW_COLOR_OPTIONS,
|
||||
} from "@/constants/constants";
|
||||
import { useGetBuildsQuery } from "@/controllers/API/queries/_builds";
|
||||
import { track } from "@/customization/utils/analytics";
|
||||
|
|
@ -196,8 +196,7 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
const zoomLevel = reactFlowInstance?.getZoom();
|
||||
const shadowBoxWidth = NOTE_NODE_MIN_WIDTH * (zoomLevel || 1);
|
||||
const shadowBoxHeight = NOTE_NODE_MIN_HEIGHT * (zoomLevel || 1);
|
||||
const shadowBoxBackgroundColor =
|
||||
SHADOW_COLOR_OPTIONS[Object.keys(SHADOW_COLOR_OPTIONS)[0]];
|
||||
const shadowBoxBackgroundColor = COLOR_OPTIONS[Object.keys(COLOR_OPTIONS)[0]];
|
||||
|
||||
function handleGroupNode() {
|
||||
takeSnapshot();
|
||||
|
|
@ -432,6 +431,11 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
const onDrop = useCallback(
|
||||
(event: React.DragEvent) => {
|
||||
event.preventDefault();
|
||||
const grabbingElement =
|
||||
document.getElementsByClassName("cursor-grabbing");
|
||||
if (grabbingElement.length > 0) {
|
||||
document.body.removeChild(grabbingElement[0]);
|
||||
}
|
||||
if (event.dataTransfer.types.some((type) => isSupportedNodeTypes(type))) {
|
||||
takeSnapshot();
|
||||
|
||||
|
|
@ -561,20 +565,6 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
[isAddingNote, setNodes, reactFlowInstance, getNodeId, setFilterEdge],
|
||||
);
|
||||
|
||||
const onPaneMouseMove = useCallback(
|
||||
(event: React.MouseEvent) => {
|
||||
if (isAddingNote) {
|
||||
const shadowBox = document.getElementById("shadow-box");
|
||||
if (shadowBox) {
|
||||
shadowBox.style.display = "block";
|
||||
shadowBox.style.left = `${event.clientX - shadowBoxWidth / 2}px`;
|
||||
shadowBox.style.top = `${event.clientY - shadowBoxHeight / 2}px`;
|
||||
}
|
||||
}
|
||||
},
|
||||
[isAddingNote],
|
||||
);
|
||||
|
||||
const handleEdgeClick = (event, edge) => {
|
||||
const color =
|
||||
nodeColorsName[edge?.data?.targetHandle?.inputTypes[0]] ||
|
||||
|
|
@ -588,6 +578,25 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
|
||||
const { open } = useSidebar();
|
||||
|
||||
useEffect(() => {
|
||||
const handleGlobalMouseMove = (event) => {
|
||||
if (isAddingNote) {
|
||||
const shadowBox = document.getElementById("shadow-box");
|
||||
if (shadowBox) {
|
||||
shadowBox.style.display = "block";
|
||||
shadowBox.style.left = `${event.clientX - shadowBoxWidth / 2}px`;
|
||||
shadowBox.style.top = `${event.clientY - shadowBoxHeight / 2}px`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", handleGlobalMouseMove);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousemove", handleGlobalMouseMove);
|
||||
};
|
||||
}, [isAddingNote, shadowBoxWidth, shadowBoxHeight]);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full bg-canvas" ref={reactFlowWrapper}>
|
||||
{showCanvas ? (
|
||||
|
|
@ -625,10 +634,9 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
panActivationKeyCode={""}
|
||||
proOptions={{ hideAttribution: true }}
|
||||
onPaneClick={onPaneClick}
|
||||
onPaneMouseMove={onPaneMouseMove}
|
||||
onEdgeClick={handleEdgeClick}
|
||||
>
|
||||
<Background className="" />
|
||||
<Background size={2} gap={20} className="" />
|
||||
{!view && (
|
||||
<>
|
||||
<CanvasControls>
|
||||
|
|
@ -637,6 +645,12 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
tooltipText="Add Note"
|
||||
onClick={() => {
|
||||
setIsAddingNote(true);
|
||||
const shadowBox = document.getElementById("shadow-box");
|
||||
if (shadowBox) {
|
||||
shadowBox.style.display = "block";
|
||||
shadowBox.style.left = `${position.current.x - shadowBoxWidth / 2}px`;
|
||||
shadowBox.style.top = `${position.current.y - shadowBoxHeight / 2}px`;
|
||||
}
|
||||
}}
|
||||
iconClasses="text-primary"
|
||||
testId="add_note"
|
||||
|
|
@ -678,6 +692,7 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
|
|||
width: `${shadowBoxWidth}px`,
|
||||
height: `${shadowBoxHeight}px`,
|
||||
backgroundColor: `${shadowBoxBackgroundColor}`,
|
||||
opacity: 0.7,
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
></div>
|
||||
|
|
|
|||
|
|
@ -5,18 +5,25 @@ import { Button } from "@/components/ui/button";
|
|||
export function SidebarFilterComponent({
|
||||
isInput,
|
||||
type,
|
||||
color,
|
||||
resetFilters,
|
||||
}: {
|
||||
isInput: boolean;
|
||||
type: string;
|
||||
color: string;
|
||||
resetFilters: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="mb-0.5 flex w-full items-center justify-between rounded border bg-accent-indigo p-2 text-sm text-foreground">
|
||||
<div
|
||||
className={`mb-0.5 flex w-full items-center justify-between rounded border p-2 text-sm text-foreground`}
|
||||
style={{
|
||||
backgroundColor: `hsl(var(--inner-${color}-foreground))`,
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-1 items-center gap-1.5">
|
||||
<ForwardedIconComponent
|
||||
name="ListFilter"
|
||||
className="h-4 w-4 shrink-0 stroke-2 text-accent-indigo-foreground"
|
||||
className={`h-4 w-4 shrink-0 stroke-2`}
|
||||
/>
|
||||
<div className="flex flex-1">
|
||||
{isInput ? "Input" : "Output"}:{" "}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ export const SidebarDraggableComponent = forwardRef(
|
|||
official,
|
||||
beta,
|
||||
legacy,
|
||||
disabled,
|
||||
disabledTooltip,
|
||||
}: {
|
||||
sectionName: string;
|
||||
apiClass: APIClassType;
|
||||
|
|
@ -49,6 +51,8 @@ export const SidebarDraggableComponent = forwardRef(
|
|||
official: boolean;
|
||||
beta: boolean;
|
||||
legacy: boolean;
|
||||
disabled?: boolean;
|
||||
disabledTooltip?: string;
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
|
|
@ -103,116 +107,129 @@ export const SidebarDraggableComponent = forwardRef(
|
|||
open={open}
|
||||
key={itemName}
|
||||
>
|
||||
<div
|
||||
onPointerDown={handlePointerDown}
|
||||
onContextMenuCapture={(e) => {
|
||||
e.preventDefault();
|
||||
setOpen(true);
|
||||
}}
|
||||
key={itemName}
|
||||
data-tooltip-id={itemName}
|
||||
tabIndex={0}
|
||||
onKeyDown={handleKeyDown}
|
||||
className="rounded-md outline-none ring-ring focus-visible:ring-2"
|
||||
<ShadTooltip
|
||||
content={disabled ? disabledTooltip : null}
|
||||
styleClasses="z-50"
|
||||
>
|
||||
<div
|
||||
data-testid={sectionName + display_name}
|
||||
id={sectionName + display_name}
|
||||
className={cn(
|
||||
"group/draggable flex cursor-grab items-center gap-2 rounded-md bg-muted p-3 hover:bg-secondary-hover/75",
|
||||
error ? "cursor-not-allowed select-none" : "",
|
||||
)}
|
||||
draggable={!error}
|
||||
style={{
|
||||
borderLeftColor: color,
|
||||
}}
|
||||
onDragStart={onDragStart}
|
||||
onDragEnd={() => {
|
||||
document.body.removeChild(
|
||||
document.getElementsByClassName("cursor-grabbing")[0],
|
||||
);
|
||||
onPointerDown={handlePointerDown}
|
||||
onContextMenuCapture={(e) => {
|
||||
e.preventDefault();
|
||||
setOpen(true);
|
||||
}}
|
||||
key={itemName}
|
||||
data-tooltip-id={itemName}
|
||||
tabIndex={0}
|
||||
onKeyDown={handleKeyDown}
|
||||
className="rounded-md outline-none ring-ring focus-visible:ring-2"
|
||||
>
|
||||
<ForwardedIconComponent name={icon} className="h-5 w-5 shrink-0" />
|
||||
<div className="flex flex-1 items-center overflow-hidden">
|
||||
<ShadTooltip content={display_name} styleClasses="z-50">
|
||||
<span className="truncate text-sm font-semibold">
|
||||
{display_name}
|
||||
</span>
|
||||
</ShadTooltip>
|
||||
{beta && (
|
||||
<Badge
|
||||
variant="pinkStatic"
|
||||
size="sq"
|
||||
className="ml-1.5 shrink-0"
|
||||
>
|
||||
BETA
|
||||
</Badge>
|
||||
<div
|
||||
data-testid={sectionName + display_name}
|
||||
id={sectionName + display_name}
|
||||
className={cn(
|
||||
"group/draggable flex cursor-grab items-center gap-2 rounded-md bg-muted p-3 hover:bg-secondary-hover/75",
|
||||
error && "cursor-not-allowed select-none",
|
||||
disabled
|
||||
? "pointer-events-none bg-accent text-placeholder-foreground"
|
||||
: "bg-muted text-foreground",
|
||||
)}
|
||||
{legacy && (
|
||||
<Badge
|
||||
variant="secondaryStatic"
|
||||
size="sq"
|
||||
className="ml-1.5 shrink-0"
|
||||
>
|
||||
LEGACY
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
tabIndex={-1}
|
||||
className="text-primary"
|
||||
onClick={() => addComponent(apiClass, itemName)}
|
||||
>
|
||||
<ForwardedIconComponent
|
||||
name="Plus"
|
||||
className="h-4 w-4 shrink-0 transition-all group-hover/draggable:opacity-100 group-focus/draggable:opacity-100 sm:opacity-0"
|
||||
/>
|
||||
</Button>
|
||||
<div ref={popoverRef}>
|
||||
<ForwardedIconComponent
|
||||
name="GripVertical"
|
||||
className="h-4 w-4 shrink-0 text-muted-foreground group-hover/draggable:text-primary"
|
||||
/>
|
||||
<SelectTrigger tabIndex={-1}></SelectTrigger>
|
||||
<SelectContent
|
||||
position="popper"
|
||||
side="bottom"
|
||||
sideOffset={-25}
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: cursorPos.x,
|
||||
top: cursorPos.y,
|
||||
}}
|
||||
>
|
||||
<SelectItem value={"download"}>
|
||||
<div className="flex">
|
||||
<IconComponent
|
||||
name="Download"
|
||||
className="relative top-0.5 mr-2 h-4 w-4"
|
||||
/>{" "}
|
||||
Download{" "}
|
||||
</div>{" "}
|
||||
</SelectItem>
|
||||
{!official && (
|
||||
<SelectItem value={"delete"}>
|
||||
draggable={!error}
|
||||
style={{
|
||||
borderLeftColor: color,
|
||||
}}
|
||||
onDragStart={onDragStart}
|
||||
onDragEnd={() => {
|
||||
document.body.removeChild(
|
||||
document.getElementsByClassName("cursor-grabbing")[0],
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ForwardedIconComponent
|
||||
name={icon}
|
||||
className="h-5 w-5 shrink-0"
|
||||
/>
|
||||
<div className="flex flex-1 items-center overflow-hidden">
|
||||
<ShadTooltip content={display_name} styleClasses="z-50">
|
||||
<span className="truncate text-sm font-semibold">
|
||||
{display_name}
|
||||
</span>
|
||||
</ShadTooltip>
|
||||
{beta && (
|
||||
<Badge
|
||||
variant="pinkStatic"
|
||||
size="xq"
|
||||
className="ml-1.5 shrink-0"
|
||||
>
|
||||
BETA
|
||||
</Badge>
|
||||
)}
|
||||
{legacy && (
|
||||
<Badge
|
||||
variant="secondaryStatic"
|
||||
size="xq"
|
||||
className="ml-1.5 shrink-0"
|
||||
>
|
||||
LEGACY
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
tabIndex={-1}
|
||||
className="text-primary"
|
||||
onClick={() => addComponent(apiClass, itemName)}
|
||||
>
|
||||
<ForwardedIconComponent
|
||||
name="Plus"
|
||||
className="h-4 w-4 shrink-0 transition-all group-hover/draggable:opacity-100 group-focus/draggable:opacity-100 sm:opacity-0"
|
||||
/>
|
||||
</Button>
|
||||
)}
|
||||
<div ref={popoverRef}>
|
||||
<ForwardedIconComponent
|
||||
name="GripVertical"
|
||||
className="h-4 w-4 shrink-0 text-muted-foreground group-hover/draggable:text-primary"
|
||||
/>
|
||||
<SelectTrigger tabIndex={-1}></SelectTrigger>
|
||||
<SelectContent
|
||||
position="popper"
|
||||
side="bottom"
|
||||
sideOffset={-25}
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: cursorPos.x,
|
||||
top: cursorPos.y,
|
||||
}}
|
||||
>
|
||||
<SelectItem value={"download"}>
|
||||
<div className="flex">
|
||||
<IconComponent
|
||||
name="Trash2"
|
||||
name="Download"
|
||||
className="relative top-0.5 mr-2 h-4 w-4"
|
||||
/>{" "}
|
||||
Delete{" "}
|
||||
Download{" "}
|
||||
</div>{" "}
|
||||
</SelectItem>
|
||||
)}
|
||||
</SelectContent>
|
||||
{!official && (
|
||||
<SelectItem value={"delete"}>
|
||||
<div className="flex">
|
||||
<IconComponent
|
||||
name="Trash2"
|
||||
className="relative top-0.5 mr-2 h-4 w-4"
|
||||
/>{" "}
|
||||
Delete{" "}
|
||||
</div>{" "}
|
||||
</SelectItem>
|
||||
)}
|
||||
</SelectContent>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ShadTooltip>
|
||||
</Select>
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import { Switch } from "@/components/ui/switch";
|
|||
import { CustomLink } from "@/customization/components/custom-link";
|
||||
import { useAddComponent } from "@/hooks/useAddComponent";
|
||||
import { useStoreStore } from "@/stores/storeStore";
|
||||
import { checkChatInput } from "@/utils/reactflowUtils";
|
||||
import {
|
||||
nodeColors,
|
||||
SIDEBAR_BUNDLES,
|
||||
|
|
@ -97,6 +98,7 @@ export function FlowSidebarComponent() {
|
|||
(category) => Object.keys(category).length > 0,
|
||||
);
|
||||
}, [dataFilter]);
|
||||
const [sortedCategories, setSortedCategories] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
filterComponents();
|
||||
|
|
@ -128,6 +130,7 @@ export function FlowSidebarComponent() {
|
|||
// Apply search filter
|
||||
if (search && fuse) {
|
||||
const results = fuse.search(search);
|
||||
setSortedCategories(results.map((result) => result.item.category));
|
||||
filteredData = Object.fromEntries(
|
||||
Object.entries(data).map(([category, items]) => {
|
||||
const categoryResults = results.filter(
|
||||
|
|
@ -303,12 +306,21 @@ export function FlowSidebarComponent() {
|
|||
dataFilter[item.name] && Object.keys(dataFilter[item.name]).length > 0,
|
||||
);
|
||||
|
||||
const hasCategoryItems = categories.some(
|
||||
(item) =>
|
||||
dataFilter[item.name] && Object.keys(dataFilter[item.name]).length > 0,
|
||||
);
|
||||
|
||||
function handleClearSearch() {
|
||||
setSearch("");
|
||||
setFilterData(data);
|
||||
setOpenCategories([]);
|
||||
}
|
||||
|
||||
const nodes = useFlowStore((state) => state.nodes);
|
||||
|
||||
const chatInputAdded = checkChatInput(nodes);
|
||||
|
||||
return (
|
||||
<Sidebar collapsible="offcanvas" data-testid="shad-sidebar">
|
||||
<SidebarHeader className="flex w-full flex-col gap-4 p-4 pb-1">
|
||||
|
|
@ -339,12 +351,11 @@ export function FlowSidebarComponent() {
|
|||
<div className="flex flex-col gap-7 border-b pb-7 pt-5">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-sm font-medium">
|
||||
Show{" "}
|
||||
<Badge variant="pinkStatic" size="sq">
|
||||
<span className="flex gap-2 text-sm font-medium">
|
||||
Show
|
||||
<Badge variant="pinkStatic" size="xq">
|
||||
BETA
|
||||
</Badge>{" "}
|
||||
Components
|
||||
</Badge>
|
||||
</span>
|
||||
</div>
|
||||
<Switch
|
||||
|
|
@ -355,12 +366,11 @@ export function FlowSidebarComponent() {
|
|||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-sm font-medium">
|
||||
Show{" "}
|
||||
<Badge variant="secondaryStatic" size="sq">
|
||||
<span className="flex gap-2 text-sm font-medium">
|
||||
Show
|
||||
<Badge variant="secondaryStatic" size="xq">
|
||||
LEGACY
|
||||
</Badge>{" "}
|
||||
Components
|
||||
</Badge>
|
||||
</span>
|
||||
</div>
|
||||
<Switch
|
||||
|
|
@ -393,8 +403,7 @@ export function FlowSidebarComponent() {
|
|||
Type{" "}
|
||||
<span>
|
||||
<ShortcutDisplay sidebar shortcut="/" />
|
||||
</span>{" "}
|
||||
to search components
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -402,6 +411,7 @@ export function FlowSidebarComponent() {
|
|||
<SidebarFilterComponent
|
||||
isInput={!!filterType.source}
|
||||
type={filterType.type}
|
||||
color={filterType.color}
|
||||
resetFilters={() => {
|
||||
setFilterEdge([]);
|
||||
setFilterData(data);
|
||||
|
|
@ -409,19 +419,186 @@ export function FlowSidebarComponent() {
|
|||
/>
|
||||
)}
|
||||
</SidebarHeader>
|
||||
<SidebarContent className="p-2">
|
||||
<SidebarContent>
|
||||
{hasResults ? (
|
||||
<>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{!data
|
||||
? Array.from({ length: 5 }).map((_, index) => (
|
||||
<SidebarMenuItem key={index}>
|
||||
<SidebarMenuSkeleton />
|
||||
</SidebarMenuItem>
|
||||
))
|
||||
: categories.map(
|
||||
{hasCategoryItems && (
|
||||
<SidebarGroup className="p-3">
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{!data
|
||||
? Array.from({ length: 5 }).map((_, index) => (
|
||||
<SidebarMenuItem key={index}>
|
||||
<SidebarMenuSkeleton />
|
||||
</SidebarMenuItem>
|
||||
))
|
||||
: categories
|
||||
.toSorted(
|
||||
(a, b) =>
|
||||
(search !== ""
|
||||
? sortedCategories
|
||||
: categories
|
||||
).findIndex((value) => value === a.name) -
|
||||
(search !== ""
|
||||
? sortedCategories
|
||||
: categories
|
||||
).findIndex((value) => value === b.name),
|
||||
)
|
||||
.map(
|
||||
(item) =>
|
||||
dataFilter[item.name] &&
|
||||
Object.keys(dataFilter[item.name]).length > 0 && (
|
||||
<Disclosure
|
||||
key={item.name}
|
||||
open={openCategories.includes(item.name)}
|
||||
onOpenChange={(isOpen) => {
|
||||
setOpenCategories((prev) =>
|
||||
isOpen
|
||||
? [...prev, item.name]
|
||||
: prev.filter(
|
||||
(cat) => cat !== item.name,
|
||||
),
|
||||
);
|
||||
}}
|
||||
>
|
||||
<SidebarMenuItem>
|
||||
<DisclosureTrigger className="group/collapsible">
|
||||
<SidebarMenuButton asChild>
|
||||
<div
|
||||
data-testid={`disclosure-${item.display_name.toLocaleLowerCase()}`}
|
||||
tabIndex={0}
|
||||
onKeyDown={(e) =>
|
||||
handleKeyDown(e, item.name)
|
||||
}
|
||||
className="flex cursor-pointer items-center gap-2"
|
||||
>
|
||||
<ForwardedIconComponent
|
||||
name={item.icon}
|
||||
className="h-4 w-4 group-aria-expanded/collapsible:text-accent-pink-foreground"
|
||||
/>
|
||||
<span className="flex-1 group-aria-expanded/collapsible:font-semibold">
|
||||
{item.display_name}
|
||||
</span>
|
||||
<ForwardedIconComponent
|
||||
name="ChevronRight"
|
||||
className="-mr-1 h-4 w-4 text-muted-foreground transition-all group-aria-expanded/collapsible:rotate-90"
|
||||
/>
|
||||
</div>
|
||||
</SidebarMenuButton>
|
||||
</DisclosureTrigger>
|
||||
<DisclosureContent>
|
||||
<div className="flex flex-col gap-1 py-2">
|
||||
{Object.keys(dataFilter[item.name])
|
||||
.sort((a, b) =>
|
||||
sensitiveSort(
|
||||
dataFilter[item.name][a]
|
||||
.display_name,
|
||||
dataFilter[item.name][b]
|
||||
.display_name,
|
||||
),
|
||||
)
|
||||
.map((SBItemName: string, idx) => (
|
||||
<ShadTooltip
|
||||
content={
|
||||
dataFilter[item.name][
|
||||
SBItemName
|
||||
].display_name
|
||||
}
|
||||
side="right"
|
||||
key={idx}
|
||||
>
|
||||
<SidebarDraggableComponent
|
||||
sectionName={
|
||||
item.name as string
|
||||
}
|
||||
apiClass={
|
||||
dataFilter[item.name][
|
||||
SBItemName
|
||||
]
|
||||
}
|
||||
icon={
|
||||
dataFilter[item.name][
|
||||
SBItemName
|
||||
].icon ??
|
||||
item.icon ??
|
||||
"Unknown"
|
||||
}
|
||||
key={idx}
|
||||
onDragStart={(event) =>
|
||||
onDragStart(event, {
|
||||
type: removeCountFromString(
|
||||
SBItemName,
|
||||
),
|
||||
node: dataFilter[item.name][
|
||||
SBItemName
|
||||
],
|
||||
})
|
||||
}
|
||||
color={nodeColors[item.name]}
|
||||
itemName={SBItemName}
|
||||
error={
|
||||
!!dataFilter[item.name][
|
||||
SBItemName
|
||||
].error
|
||||
}
|
||||
display_name={
|
||||
dataFilter[item.name][
|
||||
SBItemName
|
||||
].display_name
|
||||
}
|
||||
official={
|
||||
dataFilter[item.name][
|
||||
SBItemName
|
||||
].official === false
|
||||
? false
|
||||
: true
|
||||
}
|
||||
beta={
|
||||
dataFilter[item.name][
|
||||
SBItemName
|
||||
].beta ?? false
|
||||
}
|
||||
legacy={
|
||||
dataFilter[item.name][
|
||||
SBItemName
|
||||
].legacy ?? false
|
||||
}
|
||||
disabled={
|
||||
SBItemName === "ChatInput" &&
|
||||
chatInputAdded
|
||||
}
|
||||
disabledTooltip="Chat input already added"
|
||||
/>
|
||||
</ShadTooltip>
|
||||
))}
|
||||
</div>
|
||||
</DisclosureContent>
|
||||
</SidebarMenuItem>
|
||||
</Disclosure>
|
||||
),
|
||||
)}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
)}
|
||||
{hasBundleItems && (
|
||||
<SidebarGroup className="p-3">
|
||||
<SidebarGroupLabel>Bundles</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{bundles
|
||||
.toSorted(
|
||||
(a, b) =>
|
||||
(search !== ""
|
||||
? sortedCategories
|
||||
: bundles
|
||||
).findIndex((value) => value === a.name) -
|
||||
(search !== ""
|
||||
? sortedCategories
|
||||
: bundles
|
||||
).findIndex((value) => value === b.name),
|
||||
)
|
||||
.map(
|
||||
(item) =>
|
||||
dataFilter[item.name] &&
|
||||
Object.keys(dataFilter[item.name]).length > 0 && (
|
||||
|
|
@ -440,7 +617,6 @@ export function FlowSidebarComponent() {
|
|||
<DisclosureTrigger className="group/collapsible">
|
||||
<SidebarMenuButton asChild>
|
||||
<div
|
||||
data-testid={`disclosure-${item.display_name.toLocaleLowerCase()}`}
|
||||
tabIndex={0}
|
||||
onKeyDown={(e) =>
|
||||
handleKeyDown(e, item.name)
|
||||
|
|
@ -449,14 +625,14 @@ export function FlowSidebarComponent() {
|
|||
>
|
||||
<ForwardedIconComponent
|
||||
name={item.icon}
|
||||
className="group-aria-expanded/collapsible:x-gradient h-4 w-4"
|
||||
className="h-4 w-4 text-muted-foreground group-aria-expanded/collapsible:text-primary"
|
||||
/>
|
||||
<span className="group-aria-expanded/collapsible:font-semibold">
|
||||
<span className="flex-1 group-aria-expanded/collapsible:font-semibold">
|
||||
{item.display_name}
|
||||
</span>
|
||||
<ForwardedIconComponent
|
||||
name="ChevronRight"
|
||||
className="h-4 w-4 text-muted-foreground transition-all group-aria-expanded/collapsible:rotate-90"
|
||||
className="-mr-1 h-4 w-4 text-muted-foreground transition-all group-aria-expanded/collapsible:rotate-90"
|
||||
/>
|
||||
</div>
|
||||
</SidebarMenuButton>
|
||||
|
|
@ -526,6 +702,11 @@ export function FlowSidebarComponent() {
|
|||
dataFilter[item.name][SBItemName]
|
||||
.legacy ?? false
|
||||
}
|
||||
disabled={
|
||||
SBItemName === "ChatInput" &&
|
||||
chatInputAdded
|
||||
}
|
||||
disabledTooltip="Chat input already added"
|
||||
/>
|
||||
</ShadTooltip>
|
||||
))}
|
||||
|
|
@ -535,126 +716,6 @@ export function FlowSidebarComponent() {
|
|||
</Disclosure>
|
||||
),
|
||||
)}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
{hasBundleItems && (
|
||||
<SidebarGroup>
|
||||
<SidebarGroupLabel>Bundles</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{bundles.map(
|
||||
(item) =>
|
||||
dataFilter[item.name] &&
|
||||
Object.keys(dataFilter[item.name]).length > 0 && (
|
||||
<Disclosure
|
||||
key={item.name}
|
||||
open={openCategories.includes(item.name)}
|
||||
onOpenChange={(isOpen) => {
|
||||
setOpenCategories((prev) =>
|
||||
isOpen
|
||||
? [...prev, item.name]
|
||||
: prev.filter((cat) => cat !== item.name),
|
||||
);
|
||||
}}
|
||||
>
|
||||
<SidebarMenuItem>
|
||||
<DisclosureTrigger className="group/collapsible">
|
||||
<SidebarMenuButton asChild>
|
||||
<div
|
||||
tabIndex={0}
|
||||
onKeyDown={(e) =>
|
||||
handleKeyDown(e, item.name)
|
||||
}
|
||||
className="flex cursor-pointer items-center gap-2"
|
||||
>
|
||||
<ForwardedIconComponent
|
||||
name={item.icon}
|
||||
className="h-4 w-4 text-muted-foreground group-aria-expanded/collapsible:text-primary"
|
||||
/>
|
||||
<span className="group-aria-expanded/collapsible:font-semibold">
|
||||
{item.display_name}
|
||||
</span>
|
||||
<ForwardedIconComponent
|
||||
name="ChevronRight"
|
||||
className="h-4 w-4 text-muted-foreground transition-all group-aria-expanded/collapsible:rotate-90"
|
||||
/>
|
||||
</div>
|
||||
</SidebarMenuButton>
|
||||
</DisclosureTrigger>
|
||||
<DisclosureContent>
|
||||
<div className="flex flex-col gap-1 py-2">
|
||||
{Object.keys(dataFilter[item.name])
|
||||
.sort((a, b) =>
|
||||
sensitiveSort(
|
||||
dataFilter[item.name][a].display_name,
|
||||
dataFilter[item.name][b].display_name,
|
||||
),
|
||||
)
|
||||
.map((SBItemName: string, idx) => (
|
||||
<ShadTooltip
|
||||
content={
|
||||
dataFilter[item.name][SBItemName]
|
||||
.display_name
|
||||
}
|
||||
side="right"
|
||||
key={idx}
|
||||
>
|
||||
<SidebarDraggableComponent
|
||||
sectionName={item.name as string}
|
||||
apiClass={
|
||||
dataFilter[item.name][SBItemName]
|
||||
}
|
||||
icon={
|
||||
dataFilter[item.name][SBItemName]
|
||||
.icon ??
|
||||
item.icon ??
|
||||
"Unknown"
|
||||
}
|
||||
key={idx}
|
||||
onDragStart={(event) =>
|
||||
onDragStart(event, {
|
||||
type: removeCountFromString(
|
||||
SBItemName,
|
||||
),
|
||||
node: dataFilter[item.name][
|
||||
SBItemName
|
||||
],
|
||||
})
|
||||
}
|
||||
color={nodeColors[item.name]}
|
||||
itemName={SBItemName}
|
||||
error={
|
||||
!!dataFilter[item.name][SBItemName]
|
||||
.error
|
||||
}
|
||||
display_name={
|
||||
dataFilter[item.name][SBItemName]
|
||||
.display_name
|
||||
}
|
||||
official={
|
||||
dataFilter[item.name][SBItemName]
|
||||
.official === false
|
||||
? false
|
||||
: true
|
||||
}
|
||||
beta={
|
||||
dataFilter[item.name][SBItemName]
|
||||
.beta ?? false
|
||||
}
|
||||
legacy={
|
||||
dataFilter[item.name][SBItemName]
|
||||
.legacy ?? false
|
||||
}
|
||||
/>
|
||||
</ShadTooltip>
|
||||
))}
|
||||
</div>
|
||||
</DisclosureContent>
|
||||
</SidebarMenuItem>
|
||||
</Disclosure>
|
||||
),
|
||||
)}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue