-
Notifications
You must be signed in to change notification settings - Fork 5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bc0dd7c
commit 53a675e
Showing
13 changed files
with
1,642 additions
and
1,122 deletions.
There are no files selected for viewing
309 changes: 128 additions & 181 deletions
309
src/frontend/src/CustomNodes/NoteNode/NoteToolbarComponent/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,220 +1,167 @@ | ||
import ShadTooltip from "@/components/common/shadTooltipComponent"; | ||
import { Button } from "@/components/ui/button"; | ||
import { | ||
Popover, | ||
PopoverContent, | ||
PopoverTrigger, | ||
} from "@/components/ui/popover"; | ||
import { | ||
Select, | ||
SelectContentWithoutPortal, | ||
SelectItem, | ||
SelectTrigger, | ||
} from "@/components/ui/select-custom"; | ||
import { Select, SelectTrigger } from "@/components/ui/select-custom"; | ||
import { COLOR_OPTIONS } from "@/constants/constants"; | ||
import ToolbarSelectItem from "@/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem"; | ||
import useAlertStore from "@/stores/alertStore"; | ||
import useFlowStore from "@/stores/flowStore"; | ||
import useFlowsManagerStore from "@/stores/flowsManagerStore"; | ||
import { useShortcutsStore } from "@/stores/shortcuts"; | ||
import { noteDataType } from "@/types/flow"; | ||
import { classNames, cn, openInNewTab } from "@/utils/utils"; | ||
import { cloneDeep } from "lodash"; | ||
import { memo, useCallback, useMemo } from "react"; | ||
import IconComponent from "../../../components/common/genericIconComponent"; | ||
import { ColorPickerButtons } from "../components/color-picker-buttons"; | ||
import { SelectItems } from "../components/select-items"; | ||
|
||
export default function NoteToolbarComponent({ | ||
const NoteToolbarComponent = memo(function NoteToolbarComponent({ | ||
data, | ||
bgColor, | ||
}: { | ||
data: noteDataType; | ||
bgColor: string; | ||
}) { | ||
const setNoticeData = useAlertStore((state) => state.setNoticeData); | ||
const nodes = useFlowStore((state) => state.nodes); | ||
const setLastCopiedSelection = useFlowStore( | ||
(state) => state.setLastCopiedSelection, | ||
); | ||
const paste = useFlowStore((state) => state.paste); | ||
const shortcuts = useShortcutsStore((state) => state.shortcuts); | ||
|
||
// Combine multiple store selectors into one to reduce re-renders | ||
const { nodes, setLastCopiedSelection, paste, setNode, deleteNode } = | ||
useFlowStore( | ||
useCallback( | ||
(state) => ({ | ||
nodes: state.nodes, | ||
setLastCopiedSelection: state.setLastCopiedSelection, | ||
paste: state.paste, | ||
setNode: state.setNode, | ||
deleteNode: state.deleteNode, | ||
}), | ||
[], | ||
), | ||
); | ||
|
||
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot); | ||
const deleteNode = useFlowStore((state) => state.deleteNode); | ||
const setNode = useFlowStore((state) => state.setNode); | ||
const shortcuts = useShortcutsStore((state) => state.shortcuts); | ||
|
||
function openDocs() { | ||
const openDocs = useCallback(() => { | ||
if (data.node?.documentation) { | ||
return openInNewTab(data.node?.documentation); | ||
} | ||
setNoticeData({ | ||
title: `${data.id} docs is not available at the moment.`, | ||
}); | ||
} | ||
}, [data.node?.documentation, data.id, setNoticeData]); | ||
|
||
const handleSelectChange = useCallback( | ||
(event: string) => { | ||
switch (event) { | ||
case "documentation": | ||
openDocs(); | ||
break; | ||
case "delete": | ||
takeSnapshot(); | ||
deleteNode(data.id); | ||
break; | ||
case "copy": | ||
const node = nodes.filter((node) => node.id === data.id); | ||
setLastCopiedSelection({ nodes: cloneDeep(node), edges: [] }); | ||
break; | ||
case "duplicate": | ||
const targetNode = nodes.find((node) => node.id === data.id); | ||
if (targetNode) { | ||
paste( | ||
{ | ||
nodes: [targetNode], | ||
edges: [], | ||
}, | ||
{ | ||
x: 50, | ||
y: 10, | ||
paneX: targetNode.position.x, | ||
paneY: targetNode.position.y, | ||
}, | ||
); | ||
} | ||
break; | ||
} | ||
}, | ||
[ | ||
openDocs, | ||
takeSnapshot, | ||
deleteNode, | ||
data.id, | ||
nodes, | ||
setLastCopiedSelection, | ||
paste, | ||
], | ||
); | ||
|
||
// Memoize the color picker background style | ||
const colorPickerStyle = useMemo( | ||
() => ({ | ||
backgroundColor: COLOR_OPTIONS[bgColor] ?? "#00000000", | ||
}), | ||
[bgColor], | ||
); | ||
|
||
const handleSelectChange = (event) => { | ||
switch (event) { | ||
case "documentation": | ||
openDocs(); | ||
break; | ||
case "delete": | ||
takeSnapshot(); | ||
deleteNode(data.id); | ||
break; | ||
case "copy": | ||
const node = nodes.filter((node) => node.id === data.id); | ||
setLastCopiedSelection({ nodes: cloneDeep(node), edges: [] }); | ||
break; | ||
case "duplicate": | ||
paste( | ||
{ | ||
nodes: [nodes.find((node) => node.id === data.id)!], | ||
edges: [], | ||
}, | ||
{ | ||
x: 50, | ||
y: 10, | ||
paneX: nodes.find((node) => node.id === data.id)?.position.x, | ||
paneY: nodes.find((node) => node.id === data.id)?.position.y, | ||
}, | ||
); | ||
break; | ||
} | ||
}; | ||
// the deafult value is allways the first one if none is provided | ||
return ( | ||
<> | ||
<div className="w-26 noflow nowheel nopan nodelete nodrag h-10"> | ||
<span className="isolate inline-flex rounded-md shadow-sm"> | ||
<Popover> | ||
<ShadTooltip content="Pick Color"> | ||
<PopoverTrigger> | ||
<div> | ||
<div className="w-26 noflow nowheel nopan nodelete nodrag h-10"> | ||
<span className="isolate inline-flex rounded-md shadow-sm"> | ||
<Popover> | ||
<ShadTooltip content="Pick Color"> | ||
<PopoverTrigger> | ||
<div> | ||
<div | ||
data-testid="color_picker" | ||
className="relative inline-flex items-center rounded-l-md bg-background px-2 py-2 text-foreground shadow-md transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" | ||
> | ||
<div | ||
data-testid="color_picker" | ||
className="relative inline-flex items-center rounded-l-md bg-background px-2 py-2 text-foreground shadow-md transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" | ||
> | ||
<div | ||
style={{ | ||
backgroundColor: COLOR_OPTIONS[bgColor] ?? "#00000000", | ||
}} | ||
className={cn( | ||
"h-4 w-4 rounded-full", | ||
COLOR_OPTIONS[bgColor] === null && "border", | ||
)} | ||
></div> | ||
</div> | ||
</div> | ||
</PopoverTrigger> | ||
</ShadTooltip> | ||
<PopoverContent side="top" className="w-fit px-2 py-2"> | ||
<div className="flew-row flex gap-3"> | ||
{Object.entries(COLOR_OPTIONS).map(([color, code]) => { | ||
return ( | ||
<Button | ||
data-testid={`color_picker_button_${color}`} | ||
unstyled | ||
key={color} | ||
onClick={() => { | ||
setNode(data.id, (old) => ({ | ||
...old, | ||
data: { | ||
...old.data, | ||
node: { | ||
...old.data.node, | ||
template: { | ||
...old.data.node?.template, | ||
backgroundColor: color, | ||
}, | ||
}, | ||
}, | ||
})); | ||
}} | ||
> | ||
<div | ||
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 ?? "#00000000", | ||
}} | ||
></div> | ||
</Button> | ||
); | ||
})} | ||
</div> | ||
</PopoverContent> | ||
</Popover> | ||
<Select onValueChange={handleSelectChange} value=""> | ||
<SelectTrigger> | ||
<ShadTooltip content="Show More" side="top"> | ||
<div> | ||
<div | ||
data-testid="more-options-modal" | ||
className={classNames( | ||
"relative -ml-px inline-flex h-8 w-[2rem] items-center rounded-r-md bg-background text-foreground shadow-md transition-all duration-500 ease-in-out hover:bg-muted focus:z-10", | ||
style={colorPickerStyle} | ||
className={cn( | ||
"h-4 w-4 rounded-full", | ||
COLOR_OPTIONS[bgColor] === null && "border", | ||
)} | ||
> | ||
<IconComponent | ||
name="MoreHorizontal" | ||
className="relative left-2 h-4 w-4" | ||
/> | ||
</div> | ||
/> | ||
</div> | ||
</ShadTooltip> | ||
</SelectTrigger> | ||
<SelectContentWithoutPortal> | ||
<SelectItem value={"duplicate"}> | ||
<ToolbarSelectItem | ||
shortcut={ | ||
shortcuts.find((obj) => obj.name === "Duplicate")?.shortcut! | ||
} | ||
value={"Duplicate"} | ||
icon={"Copy"} | ||
dataTestId="copy-button-modal" | ||
/> | ||
</SelectItem> | ||
<SelectItem value={"copy"}> | ||
<ToolbarSelectItem | ||
shortcut={ | ||
shortcuts.find((obj) => obj.name === "Copy")?.shortcut! | ||
} | ||
value={"Copy"} | ||
icon={"Clipboard"} | ||
dataTestId="copy-button-modal" | ||
/> | ||
</SelectItem> | ||
<SelectItem | ||
value={"documentation"} | ||
disabled={data.node?.documentation === ""} | ||
> | ||
<ToolbarSelectItem | ||
shortcut={ | ||
shortcuts.find((obj) => obj.name === "Docs")?.shortcut! | ||
} | ||
value={"Docs"} | ||
icon={"FileText"} | ||
dataTestId="docs-button-modal" | ||
/> | ||
</SelectItem> | ||
<SelectItem value={"delete"} className="focus:bg-red-400/[.20]"> | ||
<div className="font-red flex text-status-red"> | ||
</div> | ||
</PopoverTrigger> | ||
</ShadTooltip> | ||
<PopoverContent side="top" className="w-fit px-2 py-2"> | ||
<ColorPickerButtons | ||
bgColor={bgColor} | ||
data={data} | ||
setNode={setNode} | ||
/> | ||
</PopoverContent> | ||
</Popover> | ||
|
||
<Select onValueChange={handleSelectChange} value=""> | ||
<SelectTrigger> | ||
<ShadTooltip content="Show More" side="top"> | ||
<div> | ||
<div | ||
data-testid="more-options-modal" | ||
className={classNames( | ||
"relative -ml-px inline-flex h-8 w-[2rem] items-center rounded-r-md bg-background text-foreground shadow-md transition-all duration-500 ease-in-out hover:bg-muted focus:z-10", | ||
)} | ||
> | ||
<IconComponent | ||
name="Trash2" | ||
className="relative top-0.5 mr-2 h-4 w-4" | ||
/>{" "} | ||
<span className="">Delete</span>{" "} | ||
<span className="absolute right-2 top-2 flex items-center justify-center rounded-sm px-1 py-[0.2]"> | ||
<IconComponent | ||
name="Delete" | ||
className="h-4 w-4 stroke-2 text-red-400" | ||
></IconComponent> | ||
</span> | ||
name="MoreHorizontal" | ||
className="relative left-2 h-4 w-4" | ||
/> | ||
</div> | ||
</SelectItem> | ||
</SelectContentWithoutPortal> | ||
</Select> | ||
</span> | ||
</div> | ||
</> | ||
</div> | ||
</ShadTooltip> | ||
</SelectTrigger> | ||
<SelectItems shortcuts={shortcuts} data={data} /> | ||
</Select> | ||
</span> | ||
</div> | ||
); | ||
} | ||
}); | ||
|
||
NoteToolbarComponent.displayName = "NoteToolbarComponent"; | ||
|
||
export default NoteToolbarComponent; |
Oops, something went wrong.