Feat: add visual shortcuts to nodeToolbar tooltips
This commit is contained in:
parent
a335bb7989
commit
2bbf01deaa
3 changed files with 132 additions and 33 deletions
46
src/frontend/src/components/renderIconComponent/index.tsx
Normal file
46
src/frontend/src/components/renderIconComponent/index.tsx
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import ForwardedIconComponent from "../genericIconComponent";
|
||||||
|
|
||||||
|
export default function RenderIcons({
|
||||||
|
isMac,
|
||||||
|
hasShift,
|
||||||
|
filteredShortcut,
|
||||||
|
shortcutWPlus,
|
||||||
|
}: {
|
||||||
|
isMac: boolean;
|
||||||
|
hasShift: boolean;
|
||||||
|
filteredShortcut: string[];
|
||||||
|
shortcutWPlus: string[];
|
||||||
|
}): JSX.Element {
|
||||||
|
return hasShift ? (
|
||||||
|
<>
|
||||||
|
{isMac ? (
|
||||||
|
<ForwardedIconComponent name="Command" className="h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
filteredShortcut[0]
|
||||||
|
)}
|
||||||
|
<ForwardedIconComponent name="ArrowBigUp" className="ml-1 h-5 w-5" />
|
||||||
|
{filteredShortcut.map((key, idx) => {
|
||||||
|
if (idx > 0) {
|
||||||
|
return <span className="ml-1"> {key.toUpperCase()} </span>;
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{shortcutWPlus[0].toLowerCase() === "space" ? (
|
||||||
|
"Space"
|
||||||
|
) : shortcutWPlus[0].length <= 1 ? (
|
||||||
|
shortcutWPlus[0]
|
||||||
|
) : isMac ? (
|
||||||
|
<ForwardedIconComponent name="Command" className="h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
shortcutWPlus[0]
|
||||||
|
)}
|
||||||
|
{shortcutWPlus.map((key, idx) => {
|
||||||
|
if (idx > 0) {
|
||||||
|
return <span className="ml-0.5"> {key.toUpperCase()} </span>;
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,9 @@ import { useEffect, useState } from "react";
|
||||||
import { useHotkeys } from "react-hotkeys-hook";
|
import { useHotkeys } from "react-hotkeys-hook";
|
||||||
import { useUpdateNodeInternals } from "reactflow";
|
import { useUpdateNodeInternals } from "reactflow";
|
||||||
import CodeAreaComponent from "../../../../components/codeAreaComponent";
|
import CodeAreaComponent from "../../../../components/codeAreaComponent";
|
||||||
import IconComponent from "../../../../components/genericIconComponent";
|
import IconComponent, {
|
||||||
|
ForwardedIconComponent,
|
||||||
|
} from "../../../../components/genericIconComponent";
|
||||||
import ShadTooltip from "../../../../components/shadTooltipComponent";
|
import ShadTooltip from "../../../../components/shadTooltipComponent";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
|
|
@ -32,6 +34,7 @@ import {
|
||||||
} from "../../../../utils/reactflowUtils";
|
} from "../../../../utils/reactflowUtils";
|
||||||
import { classNames, cn } from "../../../../utils/utils";
|
import { classNames, cn } from "../../../../utils/utils";
|
||||||
import ToolbarSelectItem from "./toolbarSelectItem";
|
import ToolbarSelectItem from "./toolbarSelectItem";
|
||||||
|
import RenderIcons from "../../../../components/renderIconComponent";
|
||||||
|
|
||||||
export default function NodeToolbarComponent({
|
export default function NodeToolbarComponent({
|
||||||
data,
|
data,
|
||||||
|
|
@ -44,6 +47,7 @@ export default function NodeToolbarComponent({
|
||||||
setShowState,
|
setShowState,
|
||||||
onCloseAdvancedModal,
|
onCloseAdvancedModal,
|
||||||
}: nodeToolbarPropsType): JSX.Element {
|
}: nodeToolbarPropsType): JSX.Element {
|
||||||
|
const isMac = navigator.platform.toUpperCase().includes("MAC");
|
||||||
const nodeLength = Object.keys(data.node!.template).filter(
|
const nodeLength = Object.keys(data.node!.template).filter(
|
||||||
(templateField) =>
|
(templateField) =>
|
||||||
templateField.charAt(0) !== "_" &&
|
templateField.charAt(0) !== "_" &&
|
||||||
|
|
@ -57,7 +61,7 @@ export default function NodeToolbarComponent({
|
||||||
data.node.template[templateField].type === "Any" ||
|
data.node.template[templateField].type === "Any" ||
|
||||||
data.node.template[templateField].type === "int" ||
|
data.node.template[templateField].type === "int" ||
|
||||||
data.node.template[templateField].type === "dict" ||
|
data.node.template[templateField].type === "dict" ||
|
||||||
data.node.template[templateField].type === "NestedDict")
|
data.node.template[templateField].type === "NestedDict"),
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
const hasStore = useStoreStore((state) => state.hasStore);
|
const hasStore = useStoreStore((state) => state.hasStore);
|
||||||
|
|
@ -196,7 +200,7 @@ export default function NodeToolbarComponent({
|
||||||
const [showconfirmShare, setShowconfirmShare] = useState(false);
|
const [showconfirmShare, setShowconfirmShare] = useState(false);
|
||||||
const [showOverrideModal, setShowOverrideModal] = useState(false);
|
const [showOverrideModal, setShowOverrideModal] = useState(false);
|
||||||
const [flowComponent, setFlowComponent] = useState<FlowType>(
|
const [flowComponent, setFlowComponent] = useState<FlowType>(
|
||||||
createFlowComponent(cloneDeep(data), version)
|
createFlowComponent(cloneDeep(data), version),
|
||||||
);
|
);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
|
|
@ -215,7 +219,7 @@ export default function NodeToolbarComponent({
|
||||||
const updateNodeInternals = useUpdateNodeInternals();
|
const updateNodeInternals = useUpdateNodeInternals();
|
||||||
|
|
||||||
const setLastCopiedSelection = useFlowStore(
|
const setLastCopiedSelection = useFlowStore(
|
||||||
(state) => state.setLastCopiedSelection
|
(state) => state.setLastCopiedSelection,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||||
|
|
@ -289,7 +293,7 @@ export default function NodeToolbarComponent({
|
||||||
nodes,
|
nodes,
|
||||||
edges,
|
edges,
|
||||||
setNodes,
|
setNodes,
|
||||||
setEdges
|
setEdges,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "override":
|
case "override":
|
||||||
|
|
@ -313,20 +317,56 @@ export default function NodeToolbarComponent({
|
||||||
y: 10,
|
y: 10,
|
||||||
paneX: nodes.find((node) => node.id === data.id)?.position.x,
|
paneX: nodes.find((node) => node.id === data.id)?.position.x,
|
||||||
paneY: nodes.find((node) => node.id === data.id)?.position.y,
|
paneY: nodes.find((node) => node.id === data.id)?.position.y,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isSaved = flows.some((flow) =>
|
const isSaved = flows.some((flow) =>
|
||||||
Object.values(flow).includes(data.node?.display_name!)
|
Object.values(flow).includes(data.node?.display_name!),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function displayShortcut({
|
||||||
|
name,
|
||||||
|
shortcut,
|
||||||
|
}: {
|
||||||
|
name: string;
|
||||||
|
shortcut: string;
|
||||||
|
}): JSX.Element {
|
||||||
|
let hasShift: boolean = false;
|
||||||
|
const fixedShortcut = shortcut?.split("+");
|
||||||
|
fixedShortcut.forEach((key) => {
|
||||||
|
if (key.toLowerCase().includes("shift")) {
|
||||||
|
hasShift = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const filteredShortcut = fixedShortcut.filter(
|
||||||
|
(key) => !key.toLowerCase().includes("shift"),
|
||||||
|
);
|
||||||
|
let shortcutWPlus: string[] = [];
|
||||||
|
if (!hasShift) shortcutWPlus = filteredShortcut.join("+").split(" ");
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<span> {name} </span>
|
||||||
|
<span
|
||||||
|
className={`ml-3 flex items-center rounded-sm bg-muted px-1 py-[0.2] text-muted-foreground`}
|
||||||
|
>
|
||||||
|
<RenderIcons
|
||||||
|
isMac={isMac}
|
||||||
|
hasShift={hasShift}
|
||||||
|
filteredShortcut={filteredShortcut}
|
||||||
|
shortcutWPlus={shortcutWPlus}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const setNode = useFlowStore((state) => state.setNode);
|
const setNode = useFlowStore((state) => state.setNode);
|
||||||
|
|
||||||
const handleOnNewValue = (
|
const handleOnNewValue = (
|
||||||
newValue: string | string[] | boolean | Object[]
|
newValue: string | string[] | boolean | Object[],
|
||||||
): void => {
|
): void => {
|
||||||
if (data.node!.template[name].value !== newValue) {
|
if (data.node!.template[name].value !== newValue) {
|
||||||
takeSnapshot();
|
takeSnapshot();
|
||||||
|
|
@ -378,7 +418,14 @@ export default function NodeToolbarComponent({
|
||||||
<div className="w-26 nocopy nowheel nopan nodelete nodrag noundo h-10">
|
<div className="w-26 nocopy nowheel nopan nodelete nodrag noundo h-10">
|
||||||
<span className="isolate inline-flex rounded-md shadow-sm">
|
<span className="isolate inline-flex rounded-md shadow-sm">
|
||||||
{hasCode && (
|
{hasCode && (
|
||||||
<ShadTooltip content="Code" side="top">
|
<ShadTooltip
|
||||||
|
content={displayShortcut(
|
||||||
|
shortcuts.find(
|
||||||
|
({ name }) => name.split(" ")[0].toLowerCase() === "code",
|
||||||
|
)!,
|
||||||
|
)}
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
className="relative inline-flex items-center rounded-l-md bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
|
className="relative inline-flex items-center rounded-l-md bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -391,7 +438,14 @@ export default function NodeToolbarComponent({
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
)}
|
)}
|
||||||
{nodeLength > 0 && (
|
{nodeLength > 0 && (
|
||||||
<ShadTooltip content="Advanced Settings" side="top">
|
<ShadTooltip
|
||||||
|
content={displayShortcut(
|
||||||
|
shortcuts.find(
|
||||||
|
({ name }) => name.split(" ")[0].toLowerCase() === "advanced",
|
||||||
|
)!,
|
||||||
|
)}
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
className="relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
|
className="relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -422,10 +476,17 @@ export default function NodeToolbarComponent({
|
||||||
<IconComponent name="SaveAll" className="h-4 w-4" />
|
<IconComponent name="SaveAll" className="h-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
</ShadTooltip>*/}
|
</ShadTooltip>*/}
|
||||||
<ShadTooltip content="Freeze" side="top">
|
<ShadTooltip
|
||||||
|
content={displayShortcut(
|
||||||
|
shortcuts.find(
|
||||||
|
({ name }) => name.split(" ")[0].toLowerCase() === "freeze",
|
||||||
|
)!,
|
||||||
|
)}
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
|
"relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10",
|
||||||
)}
|
)}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -446,7 +507,7 @@ export default function NodeToolbarComponent({
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-4 w-4 transition-all",
|
"h-4 w-4 transition-all",
|
||||||
// TODO UPDATE THIS COLOR TO BE A VARIABLE
|
// TODO UPDATE THIS COLOR TO BE A VARIABLE
|
||||||
frozen ? "animate-wiggle text-ice" : ""
|
frozen ? "animate-wiggle text-ice" : "",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -468,13 +529,13 @@ export default function NodeToolbarComponent({
|
||||||
</ShadTooltip>*/}
|
</ShadTooltip>*/}
|
||||||
|
|
||||||
<Select onValueChange={handleSelectChange} value="">
|
<Select onValueChange={handleSelectChange} value="">
|
||||||
<ShadTooltip content="More" side="top">
|
<ShadTooltip content="All" side="top">
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
data-testid="more-options-modal"
|
data-testid="more-options-modal"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"relative -ml-px inline-flex h-8 w-[31px] items-center rounded-r-md bg-background text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
|
"relative -ml-px inline-flex h-8 w-[31px] items-center rounded-r-md bg-background text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import ForwardedIconComponent from "../../../../../components/genericIconComponent";
|
import ForwardedIconComponent from "../../../../../components/genericIconComponent";
|
||||||
|
import RenderIcons from "../../../../../components/renderIconComponent";
|
||||||
import { toolbarSelectItemProps } from "../../../../../types/components";
|
import { toolbarSelectItemProps } from "../../../../../types/components";
|
||||||
|
|
||||||
export default function ToolbarSelectItem({
|
export default function ToolbarSelectItem({
|
||||||
|
|
@ -9,6 +10,7 @@ export default function ToolbarSelectItem({
|
||||||
ping,
|
ping,
|
||||||
shortcut,
|
shortcut,
|
||||||
}: toolbarSelectItemProps) {
|
}: toolbarSelectItemProps) {
|
||||||
|
const isMac = navigator.platform.toUpperCase().includes("MAC");
|
||||||
let hasShift = false;
|
let hasShift = false;
|
||||||
const fixedShortcut = shortcut?.split("+");
|
const fixedShortcut = shortcut?.split("+");
|
||||||
fixedShortcut.forEach((key) => {
|
fixedShortcut.forEach((key) => {
|
||||||
|
|
@ -19,8 +21,8 @@ export default function ToolbarSelectItem({
|
||||||
const filteredShortcut = fixedShortcut.filter(
|
const filteredShortcut = fixedShortcut.filter(
|
||||||
(key) => !key.toLowerCase().includes("shift"),
|
(key) => !key.toLowerCase().includes("shift"),
|
||||||
);
|
);
|
||||||
let shortcutWPlus = "";
|
let shortcutWPlus: string[] = [];
|
||||||
if (!hasShift) shortcutWPlus = filteredShortcut.join("+");
|
if (!hasShift) shortcutWPlus = filteredShortcut.join("+").split(" ");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`flex ${style}`} data-testid={dataTestId}>
|
<div className={`flex ${style}`} data-testid={dataTestId}>
|
||||||
|
|
@ -34,22 +36,12 @@ export default function ToolbarSelectItem({
|
||||||
{value}
|
{value}
|
||||||
</span>
|
</span>
|
||||||
<span className={`absolute right-2 top-[0.43em] flex `}>
|
<span className={`absolute right-2 top-[0.43em] flex `}>
|
||||||
{hasShift ? (
|
<RenderIcons
|
||||||
<>
|
isMac={isMac}
|
||||||
{filteredShortcut[0]}
|
hasShift={hasShift}
|
||||||
<ForwardedIconComponent
|
filteredShortcut={filteredShortcut}
|
||||||
name="ArrowBigUp"
|
shortcutWPlus={shortcutWPlus}
|
||||||
className="ml-1 h-5 w-5"
|
/>
|
||||||
/>
|
|
||||||
{filteredShortcut.map((key, idx) => {
|
|
||||||
if (idx > 0) {
|
|
||||||
return <span className="ml-1"> {key.toUpperCase()} </span>;
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
shortcutWPlus
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue