diff --git a/src/frontend/src/components/AccordionComponent/index.tsx b/src/frontend/src/components/AccordionComponent/index.tsx index 3cd836c1f..1a69082fe 100644 --- a/src/frontend/src/components/AccordionComponent/index.tsx +++ b/src/frontend/src/components/AccordionComponent/index.tsx @@ -45,7 +45,9 @@ export default function AccordionComponent({ > {trigger} - {children} + + {children} + diff --git a/src/frontend/src/components/codeTabsComponent/index.tsx b/src/frontend/src/components/codeTabsComponent/index.tsx new file mode 100644 index 000000000..52d4720dc --- /dev/null +++ b/src/frontend/src/components/codeTabsComponent/index.tsx @@ -0,0 +1,544 @@ +import { Check, Clipboard, Download } from "lucide-react"; +import { useContext, useState } from "react"; +import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; +import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism"; +import AccordionComponent from "../../components/AccordionComponent"; +import ShadTooltip from "../../components/ShadTooltipComponent"; +import CodeAreaComponent from "../../components/codeAreaComponent"; +import Dropdown from "../../components/dropdownComponent"; +import FloatComponent from "../../components/floatComponent"; +import InputComponent from "../../components/inputComponent"; +import InputFileComponent from "../../components/inputFileComponent"; +import InputListComponent from "../../components/inputListComponent"; +import IntComponent from "../../components/intComponent"; +import PromptAreaComponent from "../../components/promptComponent"; +import TextAreaComponent from "../../components/textAreaComponent"; +import ToggleShadComponent from "../../components/toggleShadComponent"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "../../components/ui/table"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "../../components/ui/tabs"; +import { darkContext } from "../../contexts/darkContext"; +import { FlowType } from "../../types/flow/index"; +import { classNames } from "../../utils"; + +export default function CodeTabsComponent({ + flow, + tabs, + activeTab, + setActiveTab, + isMessage, + tweaks, +}: { + flow?: FlowType; + tabs: any; + activeTab: string; + setActiveTab: any; + isMessage?: boolean; + tweaks?: { + tweak?: any; + tweaksList?: any; + buildContent?: any; + getValue?: any; + buildTweakObject?: any; + }; +}) { + const [isCopied, setIsCopied] = useState(false); + const [openAccordion, setOpenAccordion] = useState([]); + const { dark } = useContext(darkContext); + + const copyToClipboard = () => { + if (!navigator.clipboard || !navigator.clipboard.writeText) { + return; + } + + navigator.clipboard.writeText(tabs[activeTab].code).then(() => { + setIsCopied(true); + + setTimeout(() => { + setIsCopied(false); + }, 2000); + }); + }; + + const downloadAsFile = () => { + const fileExtension = tabs[activeTab].language || ".txt"; + const suggestedFileName = `${"generated-code."}${fileExtension}`; + const fileName = window.prompt("Enter the file name.", suggestedFileName); + + if (!fileName) { + // user pressed cancel on prompt + return; + } + + const blob = new Blob([tabs[activeTab].code], { type: "text/plain" }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.download = fileName; + link.href = url; + link.style.display = "none"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + }; + + function openAccordions() { + let accordionsToOpen = []; + tweaks.tweak.current.forEach((el) => { + Object.keys(el).forEach((key) => { + if (Object.keys(el[key]).length > 0) { + accordionsToOpen.push(key); + setOpenAccordion(accordionsToOpen); + } + }); + }); + + if (accordionsToOpen.length == 0) { + setOpenAccordion([]); + } + } + return ( + { + setActiveTab(value); + if (value === "3") { + openAccordions(); + } + }} + > +
+ + {tabs.map((tab, index) => ( + + {tab.name} + + ))} + + {Number(activeTab) < 3 && ( +
+ + +
+ )} +
+ + {tabs.map((tab, index) => ( + + {index < 3 ? ( + + {tab.code} + + ) : index === 3 ? ( + <> +
+
+ {flow["data"]["nodes"].map((t: any, index) => ( +
+ {tweaks.tweaksList.current.includes(t["data"]["id"]) && ( + +
+ + + + + PARAM + + + VALUE + + + + + {Object.keys(t["data"]["node"]["template"]) + .filter( + (n) => + n.charAt(0) !== "_" && + t.data.node.template[n].show && + (t.data.node.template[n].type === "str" || + t.data.node.template[n].type === + "bool" || + t.data.node.template[n].type === + "float" || + t.data.node.template[n].type === + "code" || + t.data.node.template[n].type === + "prompt" || + t.data.node.template[n].type === + "file" || + t.data.node.template[n].type === "int") + ) + .map((n, i) => { + //console.log(t.data.node.template[n]); + + return ( + + + {n} + + +
+ {t.data.node.template[n].type === + "str" && + !t.data.node.template[n].options ? ( +
+ {t.data.node.template[n] + .list ? ( + {}} + onAddInput={(k) => { + tweaks.buildTweakObject( + t["data"]["id"], + k, + t.data.node.template[n] + ); + }} + /> + ) : t.data.node.template[n] + .multiline ? ( + +
+ { + tweaks.buildTweakObject( + t["data"]["id"], + k, + t.data.node + .template[n] + ); + }} + /> +
+
+ ) : ( + { + tweaks.buildTweakObject( + t["data"]["id"], + k, + t.data.node.template[n] + ); + }} + /> + )} +
+ ) : t.data.node.template[n].type === + "bool" ? ( +
+ {" "} + { + t.data.node.template[ + n + ].value = e; + tweaks.buildTweakObject( + t["data"]["id"], + e, + t.data.node.template[n] + ); + }} + size="small" + disabled={false} + /> +
+ ) : t.data.node.template[n].type === + "file" ? ( + +
+ {}} + fileTypes={ + t.data.node.template[n] + .fileTypes + } + suffixes={ + t.data.node.template[n] + .suffixes + } + onFileChange={( + k: any + ) => {}} + > +
+
+ ) : t.data.node.template[n].type === + "float" ? ( +
+ { + tweaks.buildTweakObject( + t["data"]["id"], + k, + t.data.node.template[n] + ); + }} + /> +
+ ) : t.data.node.template[n].type === + "str" && + t.data.node.template[n] + .options ? ( +
+ { + tweaks.buildTweakObject( + t["data"]["id"], + k, + t.data.node.template[n] + ); + }} + value={tweaks.getValue( + t.data.node.template[n] + .value, + t.data, + t.data.node.template[n] + )} + > +
+ ) : t.data.node.template[n].type === + "int" ? ( +
+ { + tweaks.buildTweakObject( + t["data"]["id"], + k, + t.data.node.template[n] + ); + }} + /> +
+ ) : t.data.node.template[n].type === + "prompt" ? ( + +
+ { + tweaks.buildTweakObject( + t["data"]["id"], + k, + t.data.node.template[n] + ); + }} + /> +
+
+ ) : t.data.node.template[n].type === + "code" ? ( + +
+ { + tweaks.buildTweakObject( + t["data"]["id"], + k, + t.data.node.template[n] + ); + }} + /> +
+
+ ) : t.data.node.template[n].type === + "Any" ? ( + "-" + ) : ( +
+ )} +
+
+
+ ); + })} +
+
+
+
+ )} + + {tweaks.tweaksList.current.length === 0 && ( + <> +
+ No tweaks are available for this flow. +
+ + )} +
+ ))} +
+
+ + ) : null} +
+ ))} +
+ ); +} diff --git a/src/frontend/src/components/ui/accordion.tsx b/src/frontend/src/components/ui/accordion.tsx index 4b5a12384..4ee52db10 100644 --- a/src/frontend/src/components/ui/accordion.tsx +++ b/src/frontend/src/components/ui/accordion.tsx @@ -46,7 +46,7 @@ const AccordionContent = React.forwardRef< { - const [activeTab, setActiveTab] = useState("0"); const [open, setOpen] = useState(false); - const [isCopied, setIsCopied] = useState(false); - const [openAccordion, setOpenAccordion] = useState([]); + const [activeTab, setActiveTab] = useState("0"); const tweak = useRef([]); const tweaksList = useRef([]); const { setTweak, getTweak, tabsState } = useContext(TabsContext); - - const copyToClipboard = () => { - if (!navigator.clipboard || !navigator.clipboard.writeText) { - return; - } - - navigator.clipboard.writeText(tabs[activeTab].code).then(() => { - setIsCopied(true); - - setTimeout(() => { - setIsCopied(false); - }, 2000); - }); - }; const pythonApiCode = getPythonApiCode(flow, tweak.current, tabsState); const curl_code = getCurlCode(flow, tweak.current, tabsState); const pythonCode = getPythonCode(flow, tweak.current, tabsState); @@ -92,6 +49,7 @@ const ApiModal = forwardRef( name: "cURL", mode: "bash", image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", code: curl_code, }, { @@ -99,12 +57,14 @@ const ApiModal = forwardRef( mode: "python", image: "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", code: pythonApiCode, }, { name: "Python Code", mode: "python", image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", code: pythonCode, }, ]); @@ -133,6 +93,7 @@ const ApiModal = forwardRef( name: "cURL", mode: "bash", image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", code: curl_code, }, { @@ -140,11 +101,13 @@ const ApiModal = forwardRef( mode: "python", image: "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", code: pythonApiCode, }, { name: "Python Code", mode: "python", + language: "py", image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", code: pythonCode, }, @@ -152,6 +115,7 @@ const ApiModal = forwardRef( name: "Tweaks", mode: "python", image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", code: pythonCode, }, ]); @@ -161,6 +125,7 @@ const ApiModal = forwardRef( name: "cURL", mode: "bash", image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", code: curl_code, }, { @@ -168,12 +133,14 @@ const ApiModal = forwardRef( mode: "python", image: "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", code: pythonApiCode, }, { name: "Python Code", mode: "python", image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", code: pythonCode, }, ]); @@ -206,7 +173,6 @@ const ApiModal = forwardRef( return self.indexOf(value) === index; }); } - function buildTweakObject(tw, changes, template) { if (template.type === "float") { changes = parseFloat(changes); @@ -286,22 +252,6 @@ const ApiModal = forwardRef( return returnValue; } - function openAccordions() { - let accordionsToOpen = []; - tweak.current.forEach((el) => { - Object.keys(el).forEach((key) => { - if (Object.keys(el[key]).length > 0) { - accordionsToOpen.push(key); - setOpenAccordion(accordionsToOpen); - } - }); - }); - - if (accordionsToOpen.length == 0) { - setOpenAccordion([]); - } - } - return ( {children} @@ -314,470 +264,19 @@ const ApiModal = forwardRef( /> - { - setActiveTab(value); - if (value === "3") { - openAccordions(); - } + -
- - {tabs.map((tab, index) => ( - - {tab.name} - - ))} - - {Number(activeTab) < 3 && ( -
- -
- )} -
- - {tabs.map((tab, index) => ( - - {index < 3 ? ( - - {tab.code} - - ) : index === 3 ? ( - <> -
-
- {flow["data"]["nodes"].map((t: any, index) => ( -
- {tweaksList.current.includes(t["data"]["id"]) && ( - -
- - - - - PARAM - - - VALUE - - - - - {Object.keys( - t["data"]["node"]["template"] - ) - .filter( - (n) => - n.charAt(0) !== "_" && - t.data.node.template[n].show && - (t.data.node.template[n].type === - "str" || - t.data.node.template[n].type === - "bool" || - t.data.node.template[n].type === - "float" || - t.data.node.template[n].type === - "code" || - t.data.node.template[n].type === - "prompt" || - t.data.node.template[n].type === - "file" || - t.data.node.template[n].type === - "int") - ) - .map((n, i) => { - //console.log(t.data.node.template[n]); - - return ( - - - {n} - - -
- {t.data.node.template[n] - .type === "str" && - !t.data.node.template[n] - .options ? ( -
- {t.data.node.template[n] - .list ? ( - {}} - onAddInput={(k) => { - buildTweakObject( - t["data"]["id"], - k, - t.data.node - .template[n] - ); - }} - /> - ) : t.data.node.template[ - n - ].multiline ? ( - -
- { - buildTweakObject( - t["data"][ - "id" - ], - k, - t.data.node - .template[n] - ); - }} - /> -
-
- ) : ( - { - buildTweakObject( - t["data"]["id"], - k, - t.data.node - .template[n] - ); - }} - /> - )} -
- ) : t.data.node.template[n] - .type === "bool" ? ( -
- {" "} - { - t.data.node.template[ - n - ].value = e; - buildTweakObject( - t["data"]["id"], - e, - t.data.node - .template[n] - ); - }} - size="small" - disabled={false} - /> -
- ) : t.data.node.template[n] - .type === "file" ? ( - -
- {}} - fileTypes={ - t.data.node - .template[n] - .fileTypes - } - suffixes={ - t.data.node - .template[n] - .suffixes - } - onFileChange={( - k: any - ) => {}} - > -
-
- ) : t.data.node.template[n] - .type === "float" ? ( -
- { - buildTweakObject( - t["data"]["id"], - k, - t.data.node - .template[n] - ); - }} - /> -
- ) : t.data.node.template[n] - .type === "str" && - t.data.node.template[n] - .options ? ( -
- { - buildTweakObject( - t["data"]["id"], - k, - t.data.node - .template[n] - ); - }} - value={getValue( - t.data.node.template[ - n - ].value, - t.data, - t.data.node.template[ - n - ] - )} - > -
- ) : t.data.node.template[n] - .type === "int" ? ( -
- { - buildTweakObject( - t["data"]["id"], - k, - t.data.node - .template[n] - ); - }} - /> -
- ) : t.data.node.template[n] - .type === "prompt" ? ( - -
- { - buildTweakObject( - t["data"]["id"], - k, - t.data.node - .template[n] - ); - }} - /> -
-
- ) : t.data.node.template[n] - .type === "code" ? ( - -
- { - buildTweakObject( - t["data"]["id"], - k, - t.data.node - .template[n] - ); - }} - /> -
-
- ) : t.data.node.template[n] - .type === "Any" ? ( - "-" - ) : ( -
- )} -
-
-
- ); - })} -
-
-
-
- )} - - {tweaksList.current.length === 0 && ( - <> -
- No tweaks are available for this flow. -
- - )} -
- ))} -
-
- - ) : null} -
- ))} -
+ />
); diff --git a/src/frontend/src/modals/baseModal/index.tsx b/src/frontend/src/modals/baseModal/index.tsx index b40f39bd1..870e8f948 100644 --- a/src/frontend/src/modals/baseModal/index.tsx +++ b/src/frontend/src/modals/baseModal/index.tsx @@ -104,7 +104,9 @@ function BaseModal({ {headerChild} -
{ContentChild}
+
+ {ContentChild} +
{ContentFooter && (
{ContentFooter}
)} diff --git a/src/frontend/src/modals/formModal/chatMessage/index.tsx b/src/frontend/src/modals/formModal/chatMessage/index.tsx index 953aed530..a441fa783 100644 --- a/src/frontend/src/modals/formModal/chatMessage/index.tsx +++ b/src/frontend/src/modals/formModal/chatMessage/index.tsx @@ -8,11 +8,11 @@ import remarkMath from "remark-math"; import MaleTechnology from "../../../assets/male-technologist.png"; import Robot from "../../../assets/robot.png"; import SanitizedHTMLWrapper from "../../../components/SanitizedHTMLWrapper"; +import CodeTabsComponent from "../../../components/codeTabsComponent"; import { THOUGHTS_ICON } from "../../../constants"; import { ChatMessageType } from "../../../types/chat"; import { classNames } from "../../../utils"; import FileCard from "../fileComponent"; -import { CodeBlock } from "./codeBlock"; export default function ChatMessage({ chat, lockChat, @@ -80,8 +80,8 @@ export default function ChatMessage({ {}} /> ) : ( diff --git a/src/frontend/src/modals/formModal/index.tsx b/src/frontend/src/modals/formModal/index.tsx index 3f2b21551..0fa13d0d5 100644 --- a/src/frontend/src/modals/formModal/index.tsx +++ b/src/frontend/src/modals/formModal/index.tsx @@ -452,7 +452,7 @@ export default function FormModal({ - +
{tabsState[ id.current diff --git a/src/frontend/tailwind.config.js b/src/frontend/tailwind.config.js index a3e0452c9..bc80dac5b 100644 --- a/src/frontend/tailwind.config.js +++ b/src/frontend/tailwind.config.js @@ -28,20 +28,6 @@ module.exports = { }, }, extend: { - keyframes: { - "accordion-down": { - from: { height: 0 }, - to: { height: "var(--radix-accordion-content-height)" }, - }, - "accordion-up": { - from: { height: "var(--radix-accordion-content-height)" }, - to: { height: 0 }, - }, - }, - animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", - }, colors: { connection: "var(--connection)", "almost-dark-gray": "var(--almost-dark-gray)", @@ -129,20 +115,6 @@ module.exports = { fontFamily: { sans: ["var(--font-sans)", ...fontFamily.sans], }, - keyframes: { - slideDown: { - from: { height: 0 }, - to: { height: "100vh" }, - }, - slideUp: { - from: { height: "var(--radix-accordion-content-height)" }, - to: { height: 0 }, - }, - }, - animation: { - "accordion-down": "slideDown 300ms ease-out", - "accordion-up": "slideUp 300ms ease-in", - }, }, },