Implementing Custom Tooltips for Custom Components Feature (#680)

This commit is contained in:
Gabriel Luiz Freitas Almeida 2023-07-24 19:04:04 -03:00 • committed by GitHub
commit e8c0eda048
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 167 additions and 43 deletions

View file

@ -14,6 +14,7 @@ import PromptAreaComponent from "../../../../components/promptComponent";
import TextAreaComponent from "../../../../components/textAreaComponent"; import TextAreaComponent from "../../../../components/textAreaComponent";
import ToggleShadComponent from "../../../../components/toggleShadComponent"; import ToggleShadComponent from "../../../../components/toggleShadComponent";
import { MAX_LENGTH_TO_SCROLL_TOOLTIP } from "../../../../constants/constants"; import { MAX_LENGTH_TO_SCROLL_TOOLTIP } from "../../../../constants/constants";
import { PopUpContext } from "../../../../contexts/popUpContext";
import { TabsContext } from "../../../../contexts/tabsContext"; import { TabsContext } from "../../../../contexts/tabsContext";
import { typesContext } from "../../../../contexts/typesContext"; import { typesContext } from "../../../../contexts/typesContext";
import { ParameterComponentType } from "../../../../types/components"; import { ParameterComponentType } from "../../../../types/components";
@ -27,6 +28,7 @@ import {
classNames, classNames,
getRandomKeyByssmm, getRandomKeyByssmm,
groupByFamily, groupByFamily,
groupByFamilyCustom,
} from "../../../../utils/utils"; } from "../../../../utils/utils";
export default function ParameterComponent({ export default function ParameterComponent({
@ -49,7 +51,8 @@ export default function ParameterComponent({
const infoHtml = useRef(null); const infoHtml = useRef(null);
const updateNodeInternals = useUpdateNodeInternals(); const updateNodeInternals = useUpdateNodeInternals();
const [position, setPosition] = useState(0); const [position, setPosition] = useState(0);
const { setTabsState, tabId, save } = useContext(TabsContext); const { setTabsState, tabId, save, flows } = useContext(TabsContext);
const { closeEdit } = useContext(PopUpContext);
// Update component position // Update component position
useEffect(() => { useEffect(() => {
@ -100,56 +103,80 @@ export default function ParameterComponent({
}, [info]); }, [info]);
useEffect(() => { useEffect(() => {
const groupedObj = groupByFamily(myData, tooltipTitle, left, data.type); let groupedObj = groupByFamily(
myData,
tooltipTitle,
left,
data.type,
flows.find((f) => f.id === tabId).data.nodes
);
refNumberComponents.current = groupedObj[0]?.type?.length; if (groupedObj?.length === 0) {
groupedObj = groupByFamilyCustom(
myData,
tooltipTitle,
left,
data.type,
flows.find((f) => f.id === tabId).data.nodes
);
}
refHtml.current = groupedObj.map((item, i) => { if (groupedObj) {
const Icon: any = nodeIconsLucide[item.family]; refNumberComponents.current = groupedObj[0]?.type?.length;
return ( refHtml.current = groupedObj.map((item, i) => {
<span const Icon: any = nodeIconsLucide[item.family];
key={getRandomKeyByssmm() + item.family + i}
className={classNames( return (
i > 0 ? "mt-2 flex items-center" : "flex items-center" <span
)} key={getRandomKeyByssmm() + item.family + i}
> className={classNames(
<div i > 0 ? "mt-2 flex items-center" : "flex items-center"
className="h-5 w-5" )}
style={{
color: nodeColors[item.family],
}}
> >
<Icon <div
className="h-5 w-5" className="h-5 w-5"
strokeWidth={1.5}
style={{ style={{
color: nodeColors[item.family] ?? nodeColors.unknown, color: nodeColors[item.family],
}} }}
/> >
</div> <Icon
<span className="ps-2 text-xs text-foreground"> className="h-5 w-5"
{nodeNames[item.family] ?? ""}{" "} strokeWidth={1.5}
<span className="text-xs"> style={{
{" "} color: nodeColors[item.family] ?? nodeColors.unknown,
{item.type === "" ? "" : " - "} }}
{item.type.split(", ").length > 2 />
? item.type.split(", ").map((el, i) => ( </div>
<React.Fragment key={el + i}> <span className="ps-2 text-xs text-foreground">
<span> {item.family !== "custom_components"
{i === item.type.split(", ").length - 1 ? nodeNames[item.family]
? el : item.component ?? ""}{" "}
: (el += `, `)} <span className="text-xs">
</span> {" "}
</React.Fragment> {item.type === "" ? "" : " - "}
)) {item.type.split(", ").length > 2
: item.type} ? item.type.split(", ").map((el, i) => (
<React.Fragment key={el + i}>
<span>
{i === item.type.split(", ").length - 1
? el
: (el += `, `)}
</span>
</React.Fragment>
))
: item.type}
</span>
</span> </span>
</span> </span>
</span> );
); });
}); }
}, [tooltipTitle]); }, [
tooltipTitle,
flows.find((f) => f.id === tabId).data.nodes.length,
closeEdit,
]);
return ( return (
<div <div
ref={ref} ref={ref}

View file

@ -11,9 +11,11 @@ import { Button } from "../../components/ui/button";
import { CODE_PROMPT_DIALOG_SUBTITLE } from "../../constants/constants"; import { CODE_PROMPT_DIALOG_SUBTITLE } from "../../constants/constants";
import { alertContext } from "../../contexts/alertContext"; import { alertContext } from "../../contexts/alertContext";
import { darkContext } from "../../contexts/darkContext"; import { darkContext } from "../../contexts/darkContext";
import { PopUpContext } from "../../contexts/popUpContext";
import { typesContext } from "../../contexts/typesContext"; import { typesContext } from "../../contexts/typesContext";
import { postCustomComponent, postValidateCode } from "../../controllers/API"; import { postCustomComponent, postValidateCode } from "../../controllers/API";
import { APIClassType } from "../../types/api"; import { APIClassType } from "../../types/api";
import { getRandomKeyByssmm } from "../../utils/utils";
import BaseModal from "../baseModal"; import BaseModal from "../baseModal";
export default function CodeAreaModal({ export default function CodeAreaModal({
@ -39,6 +41,7 @@ export default function CodeAreaModal({
const [error, setError] = useState<{ const [error, setError] = useState<{
detail: { error: string; traceback: string }; detail: { error: string; traceback: string };
}>(null); }>(null);
const { setCloseEdit } = useContext(PopUpContext);
useEffect(() => { useEffect(() => {
// if nodeClass.template has more fields other than code and dynamic is true // if nodeClass.template has more fields other than code and dynamic is true
@ -61,6 +64,7 @@ export default function CodeAreaModal({
}); });
setOpen(false); setOpen(false);
setValue(code); setValue(code);
setCloseEdit(getRandomKeyByssmm().toString());
// setValue(code); // setValue(code);
} else { } else {
if (funcErrors.length !== 0) { if (funcErrors.length !== 0) {
@ -97,6 +101,7 @@ export default function CodeAreaModal({
setNodeClass(data); setNodeClass(data);
setValue(code); setValue(code);
setOpen(false); setOpen(false);
setCloseEdit(getRandomKeyByssmm().toString());
} }
}) })
.catch((err) => { .catch((err) => {

View file

@ -5,6 +5,7 @@ import { IVarHighlightType } from "../types/components";
import { FlowType } from "../types/flow"; import { FlowType } from "../types/flow";
import { TabsState } from "../types/tabs"; import { TabsState } from "../types/tabs";
import { buildTweaks } from "./reactflowUtils"; import { buildTweaks } from "./reactflowUtils";
import { nodeNames } from "./styleUtils";
export function classNames(...classes: Array<string>) { export function classNames(...classes: Array<string>) {
return classes.filter(Boolean).join(" "); return classes.filter(Boolean).join(" ");
@ -88,12 +89,13 @@ export function checkUpperWords(str: string) {
export const isWrappedWithClass = (event: any, className: string | undefined) => export const isWrappedWithClass = (event: any, className: string | undefined) =>
event.target.closest(`.${className}`); event.target.closest(`.${className}`);
export function groupByFamily(data, baseClasses, left, type) { export function groupByFamily(data, baseClasses, left, type, flow) {
let parentOutput: string; let parentOutput: string;
let arrOfParent: string[] = []; let arrOfParent: string[] = [];
let arrOfType: { family: string; type: string; component: string }[] = []; let arrOfType: { family: string; type: string; component: string }[] = [];
let arrOfLength: { length: number; type: string }[] = []; let arrOfLength: { length: number; type: string }[] = [];
let lastType = ""; let lastType = "";
Object.keys(data).forEach((d) => { Object.keys(data).forEach((d) => {
Object.keys(data[d]).forEach((n) => { Object.keys(data[d]).forEach((n) => {
try { try {
@ -203,6 +205,96 @@ export function groupByFamily(data, baseClasses, left, type) {
} }
} }
export function groupByFamilyCustom(data, baseClasses, left, type, flow) {
let arrOfParentCustom: string[] = [];
let arrOfType: { family: string; type: string; component: string }[] = [];
if (type === "CustomComponent") {
const uniqueValuesSet = new Set();
flow.forEach((element) => {
element["data"]["node"]["base_classes"].forEach((el) => {
if (!uniqueValuesSet.has(el)) {
arrOfParentCustom.push(el);
uniqueValuesSet.add(el);
}
});
});
}
if (left === false) {
arrOfParentCustom.map((n) => {
try {
arrOfType.push({
family: "custom_components",
type: n,
component: nodeNames["custom_components"],
});
} catch (e) {
console.log(e);
}
});
} else {
flow.forEach((element) => {
Object.keys(element["data"]["node"]["template"]).map((el) => {
if (
element["data"]["node"]["template"][el].input_types &&
element["data"]["node"]["template"][el].input_types.length > 0
) {
element["data"]["node"]["template"][el].input_types.map((n) => {
try {
arrOfType.push({
family: "custom_components",
type: n,
component: nodeNames["custom_components"],
});
} catch (e) {
console.log(e);
}
});
}
});
});
}
const groupedResult = {};
arrOfType.forEach((item) => {
const { family, type, component } = item;
if (groupedResult.hasOwnProperty(family)) {
if (!groupedResult[family].type.includes(type)) {
groupedResult[family].type += `, ${type}`;
}
} else {
groupedResult[family] = { family, type, component };
}
});
const result = Object.values(groupedResult);
if (left === false) {
let resultFiltered = [];
flow.forEach((element) => {
Object.keys(element["data"]["node"]["template"]).map((el) => {
if (
element["data"]["node"]["template"][el].input_types &&
element["data"]["node"]["template"][el].input_types.length > 0
) {
element["data"]["node"]["template"][el].input_types.map((n) => {
resultFiltered.push({
family: "custom_components",
type: n,
component: element["data"]["node"]["display_name"],
});
});
}
});
});
return resultFiltered;
} else {
return result;
}
}
export function buildInputs(tabsState, id) { export function buildInputs(tabsState, id) {
return tabsState && return tabsState &&
tabsState[id] && tabsState[id] &&