NodeToolbar Feature Implementation and Dialog UI Migration (#462)
Description This pull request implements the NodeToolbar feature and migrates the dialog UI to shadCN. The NodeToolbar introduces three actions: duplicate, delete, and edit. The edit action allows users to modify the advanced configuration of the tools. Additionally, this pull request migrates the dialog UI to shadCN, specifically updating the prompt dialog, code dialog, export dialog, python functions dialog and tooltips. These enhancements improve the user experience and provide a more efficient and modern interface. Changes Made Added NodeToolbar component to the application. Implemented duplicate functionality, allowing users to create copies of the selected nodes. Implemented delete functionality, enabling users to remove selected nodes. Implemented edit functionality, providing users with the ability to modify the advanced configuration of the tools. Migrated the prompt dialog UI to shadCN, improving its appearance and functionality. Migrated the code dialog UI to shadCN, enhancing its usability and aesthetics. Migrated the export dialog UI to shadCN, resulting in a more streamlined and intuitive interface. Migrated the python functions dialog UI to shadCN, ensuring consistency with the rest of the application's design. Migrated the headlessUI tooltip to shadCN. FYI: Need to improve the dialog subtitles texts.
This commit is contained in:
commit
111252fbb2
39 changed files with 4892 additions and 2373 deletions
0
.githooks/pre-commit
Executable file → Normal file
0
.githooks/pre-commit
Executable file → Normal file
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"name": "reactFlow",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"vite-plugin-svgr": "^3.2.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4508
src/frontend/package-lock.json
generated
4508
src/frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -8,16 +8,23 @@
|
||||||
"@headlessui/react": "^1.7.10",
|
"@headlessui/react": "^1.7.10",
|
||||||
"@heroicons/react": "^2.0.15",
|
"@heroicons/react": "^2.0.15",
|
||||||
"@mui/material": "^5.11.9",
|
"@mui/material": "^5.11.9",
|
||||||
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
|
"@radix-ui/react-dialog": "^1.0.4",
|
||||||
|
"@radix-ui/react-label": "^2.0.2",
|
||||||
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
|
"@radix-ui/react-switch": "^1.0.3",
|
||||||
"@radix-ui/react-tooltip": "^1.0.6",
|
"@radix-ui/react-tooltip": "^1.0.6",
|
||||||
"@tabler/icons-react": "^2.18.0",
|
"@tabler/icons-react": "^2.18.0",
|
||||||
"@tailwindcss/forms": "^0.5.3",
|
"@tailwindcss/forms": "^0.5.3",
|
||||||
"@tailwindcss/line-clamp": "^0.4.4",
|
"@tailwindcss/line-clamp": "^0.4.4",
|
||||||
"ace-builds": "^1.16.0",
|
"ace-builds": "^1.16.0",
|
||||||
|
"add": "^2.0.6",
|
||||||
"ansi-to-html": "^0.7.2",
|
"ansi-to-html": "^0.7.2",
|
||||||
"axios": "^1.3.2",
|
"axios": "^1.3.2",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"class-variance-authority": "^0.6.0",
|
"class-variance-authority": "^0.6.0",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
|
"esbuild": "^0.17.18",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lucide-react": "^0.233.0",
|
"lucide-react": "^0.233.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
|
@ -36,6 +43,9 @@
|
||||||
"rehype-mathjax": "^4.0.2",
|
"rehype-mathjax": "^4.0.2",
|
||||||
"remark-gfm": "^3.0.1",
|
"remark-gfm": "^3.0.1",
|
||||||
"remark-math": "^5.1.1",
|
"remark-math": "^5.1.1",
|
||||||
|
"shadcn-ui": "^0.1.3",
|
||||||
|
"switch": "^0.0.0",
|
||||||
|
"table": "^6.8.1",
|
||||||
"tailwind-merge": "^1.13.0",
|
"tailwind-merge": "^1.13.0",
|
||||||
"tailwindcss-animate": "^1.0.5",
|
"tailwindcss-animate": "^1.0.5",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
|
|
@ -69,6 +79,8 @@
|
||||||
},
|
},
|
||||||
"proxy": "http://127.0.0.1:7860",
|
"proxy": "http://127.0.0.1:7860",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@swc/cli": "^0.1.62",
|
||||||
|
"@swc/core": "^1.3.62",
|
||||||
"@tailwindcss/typography": "^0.5.9",
|
"@tailwindcss/typography": "^0.5.9",
|
||||||
"@testing-library/jest-dom": "^5.16.5",
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,10 @@ export default function App() {
|
||||||
</div>
|
</div>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
<div></div>
|
<div></div>
|
||||||
<div className="flex z-40 flex-col-reverse fixed bottom-5 left-5">
|
<div
|
||||||
|
className="flex flex-col-reverse fixed bottom-5 left-5"
|
||||||
|
style={{ zIndex: 999 }}
|
||||||
|
>
|
||||||
{alertsList.map((alert) => (
|
{alertsList.map((alert) => (
|
||||||
<div key={alert.id}>
|
<div key={alert.id}>
|
||||||
{alert.type === "error" ? (
|
{alert.type === "error" ? (
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ export default function ParameterComponent({
|
||||||
setPosition(ref.current.offsetTop + ref.current.clientHeight / 2);
|
setPosition(ref.current.offsetTop + ref.current.clientHeight / 2);
|
||||||
updateNodeInternals(data.id);
|
updateNodeInternals(data.id);
|
||||||
}
|
}
|
||||||
}, [data.id, ref, updateNodeInternals]);
|
}, [data.id, ref, ref.current, ref.current?.offsetTop, updateNodeInternals]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateNodeInternals(data.id);
|
updateNodeInternals(data.id);
|
||||||
|
|
@ -65,7 +65,7 @@ export default function ParameterComponent({
|
||||||
|
|
||||||
refHtml.current = groupedObj.map((item, i) => (
|
refHtml.current = groupedObj.map((item, i) => (
|
||||||
<span
|
<span
|
||||||
key={item}
|
key={i}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
i > 0 ? "items-center flex mt-3" : "items-center flex"
|
i > 0 ? "items-center flex mt-3" : "items-center flex"
|
||||||
)}
|
)}
|
||||||
|
|
@ -86,7 +86,7 @@ export default function ParameterComponent({
|
||||||
{item.type.split(", ").length > 2
|
{item.type.split(", ").length > 2
|
||||||
? item.type.split(", ").map((el, i) => (
|
? item.type.split(", ").map((el, i) => (
|
||||||
<>
|
<>
|
||||||
<span key={el}>
|
<span key={i}>
|
||||||
{i == item.type.split(", ").length - 1
|
{i == item.type.split(", ").length - 1
|
||||||
? el
|
? el
|
||||||
: (el += `, `)}
|
: (el += `, `)}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ import { useCallback } from "react";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { debounce } from "../../utils";
|
import { debounce } from "../../utils";
|
||||||
import Tooltip from "../../components/TooltipComponent";
|
import Tooltip from "../../components/TooltipComponent";
|
||||||
|
import { NodeToolbar } from "reactflow";
|
||||||
|
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
||||||
|
|
||||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||||
export default function GenericNode({
|
export default function GenericNode({
|
||||||
data,
|
data,
|
||||||
|
|
@ -97,9 +100,17 @@ export default function GenericNode({
|
||||||
deleteNode(data.id);
|
deleteNode(data.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<NodeToolbar>
|
||||||
|
<NodeToolbarComponent
|
||||||
|
data={data}
|
||||||
|
openPopUp={openPopUp}
|
||||||
|
deleteNode={deleteNode}
|
||||||
|
></NodeToolbarComponent>
|
||||||
|
</NodeToolbar>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
selected ? "border border-blue-500" : "border dark:border-gray-700",
|
selected ? "border border-blue-500" : "border dark:border-gray-700",
|
||||||
|
|
@ -127,37 +138,9 @@ export default function GenericNode({
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
openPopUp(<NodeModal data={data} />);
|
openPopUp(<NodeModal data={data} />);
|
||||||
}}
|
}}
|
||||||
>
|
></button>
|
||||||
<div className=" absolute -right-1 -top-2 text-red-600">
|
|
||||||
{Object.keys(data.node.template).some(
|
|
||||||
(t) =>
|
|
||||||
data.node.template[t].advanced &&
|
|
||||||
data.node.template[t].required
|
|
||||||
)
|
|
||||||
? " *"
|
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
<Cog6ToothIcon
|
<div className="flex gap-3">
|
||||||
className={classNames(
|
|
||||||
Object.keys(data.node.template).some(
|
|
||||||
(t) =>
|
|
||||||
data.node.template[t].advanced && data.node.template[t].show
|
|
||||||
)
|
|
||||||
? ""
|
|
||||||
: "hidden",
|
|
||||||
"w-5 h-5 dark:text-gray-300"
|
|
||||||
)}
|
|
||||||
></Cog6ToothIcon>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
deleteNode(data.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<TrashIcon className="w-5 h-5 dark:text-gray-300"></TrashIcon>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
|
|
@ -165,7 +148,9 @@ export default function GenericNode({
|
||||||
"Validating..."
|
"Validating..."
|
||||||
) : (
|
) : (
|
||||||
<div className="max-h-96 overflow-auto">
|
<div className="max-h-96 overflow-auto">
|
||||||
{validationStatus.params.split("\n").map((line, index) => (
|
{validationStatus.params
|
||||||
|
.split("\n")
|
||||||
|
.map((line, index) => (
|
||||||
<div key={index}>{line}</div>
|
<div key={index}>{line}</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -282,5 +267,6 @@ export default function GenericNode({
|
||||||
</>
|
</>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ export default function CodeAreaComponent({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
disabled,
|
disabled,
|
||||||
|
editNode = false,
|
||||||
}: TextAreaComponentType) {
|
}: TextAreaComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value);
|
const [myValue, setMyValue] = useState(value);
|
||||||
const { openPopUp } = useContext(PopUpContext);
|
const { openPopUp } = useContext(PopUpContext);
|
||||||
|
|
@ -38,7 +39,9 @@ export default function CodeAreaComponent({
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
"truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
editNode
|
||||||
|
? "h-7 truncate placeholder:text-center text-gray-500 border-0 block w-full pt-0.5 pb-0.5 form-input dark:bg-gray-900 dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm sm:text-sm focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200"
|
||||||
|
: "truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
||||||
(disabled ? " bg-gray-200" : "")
|
(disabled ? " bg-gray-200" : "")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -57,7 +60,9 @@ export default function CodeAreaComponent({
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{!editNode && (
|
||||||
<ArrowTopRightOnSquareIcon className="w-6 h-6 hover:text-blue-600 dark:text-gray-300" />
|
<ArrowTopRightOnSquareIcon className="w-6 h-6 hover:text-blue-600 dark:text-gray-300" />
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,12 @@ export default function Dropdown({
|
||||||
value,
|
value,
|
||||||
options,
|
options,
|
||||||
onSelect,
|
onSelect,
|
||||||
|
editNode = false,
|
||||||
}: DropDownComponentType) {
|
}: DropDownComponentType) {
|
||||||
let [internalValue, setInternalValue] = useState(
|
let [internalValue, setInternalValue] = useState(
|
||||||
value === "" || !value ? "Choose an option" : value
|
value === "" || !value ? "Choose an option" : value
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Listbox
|
<Listbox
|
||||||
|
|
@ -23,12 +25,26 @@ export default function Dropdown({
|
||||||
>
|
>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
<div className="relative mt-1 w-full">
|
<div
|
||||||
<Listbox.Button className="relative w-full cursor-default rounded-md border border-gray-300 bg-white dark:bg-gray-900 py-2 pl-3 pr-10 text-left shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 sm:text-sm">
|
className={
|
||||||
<span className="block truncate w-full dark:text-gray-300">
|
editNode ? "relative mt-0 w-full" : "relative mt-1 w-full"
|
||||||
{internalValue}
|
}
|
||||||
</span>
|
>
|
||||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
<Listbox.Button
|
||||||
|
className={
|
||||||
|
editNode
|
||||||
|
? "pr-9 arrow-hide placeholder:text-center border-0 block w-full pt-0.5 pb-0.5 form-input dark:bg-gray-900 dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm sm:text-sm focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200"
|
||||||
|
: "relative w-full cursor-default rounded-md border border-gray-300 bg-white dark:bg-gray-900 py-2 pl-3 pr-10 text-left shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 sm:text-sm"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="block truncate w-full">{internalValue}</span>
|
||||||
|
<span
|
||||||
|
className={
|
||||||
|
editNode
|
||||||
|
? "hidden"
|
||||||
|
: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2"
|
||||||
|
}
|
||||||
|
>
|
||||||
<ChevronUpDownIcon
|
<ChevronUpDownIcon
|
||||||
className="h-5 w-5 text-gray-400"
|
className="h-5 w-5 text-gray-400"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
|
|
@ -43,16 +59,27 @@ export default function Dropdown({
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<Listbox.Options className="absolute z-10 mt-1 max-h-60 w-full dark:bg-gray-800 overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
<Listbox.Options
|
||||||
|
className={
|
||||||
|
editNode
|
||||||
|
? "arrow-hide"
|
||||||
|
: "absolute z-50 mt-1 max-h-60 w-full dark:bg-gray-800 overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
|
||||||
|
}
|
||||||
|
>
|
||||||
{options.map((option, id) => (
|
{options.map((option, id) => (
|
||||||
<Listbox.Option
|
<Listbox.Option
|
||||||
key={id}
|
key={id}
|
||||||
className={({ active }) =>
|
className={({ active }) =>
|
||||||
classNames(
|
classNames(
|
||||||
active
|
active && !editNode
|
||||||
? "text-white bg-indigo-600 dark:bg-indigo-500"
|
? "text-white bg-indigo-600 dark:bg-indigo-500"
|
||||||
: "text-gray-900",
|
: "text-gray-900",
|
||||||
"relative cursor-default select-none py-2 pl-3 pr-9 dark:text-gray-300 dark:bg-gray-800"
|
active && editNode
|
||||||
|
? "text-white bg-gray-400 dark:bg-gray-500"
|
||||||
|
: "",
|
||||||
|
editNode
|
||||||
|
? "relative cursor-default select-none py-0.5 pl-3 pr-12 dark:text-gray-300 dark:bg-gray-800"
|
||||||
|
: "relative cursor-default select-none py-2 pl-3 pr-9 dark:text-gray-300 dark:bg-gray-800"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
value={option}
|
value={option}
|
||||||
|
|
@ -71,7 +98,8 @@ export default function Dropdown({
|
||||||
{selected ? (
|
{selected ? (
|
||||||
<span
|
<span
|
||||||
className={classNames(
|
className={classNames(
|
||||||
active ? "text-white" : "text-indigo-600",
|
editNode ? "text-gray-600" : "text-indigo-600",
|
||||||
|
active ? "text-white" : "",
|
||||||
"absolute inset-y-0 right-0 flex items-center pr-4"
|
"absolute inset-y-0 right-0 flex items-center pr-4"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export default function FloatComponent({
|
||||||
onChange,
|
onChange,
|
||||||
disableCopyPaste = false,
|
disableCopyPaste = false,
|
||||||
disabled,
|
disabled,
|
||||||
|
editNode = false,
|
||||||
}: FloatComponentType) {
|
}: FloatComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value ?? "");
|
const [myValue, setMyValue] = useState(value ?? "");
|
||||||
const { setDisableCopyPaste } = useContext(TabsContext);
|
const { setDisableCopyPaste } = useContext(TabsContext);
|
||||||
|
|
@ -33,10 +34,14 @@ export default function FloatComponent({
|
||||||
type="number"
|
type="number"
|
||||||
value={myValue}
|
value={myValue}
|
||||||
className={
|
className={
|
||||||
"block w-full form-input dark:bg-gray-900 arrow-hide dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
editNode
|
||||||
|
? "text-center arrow-hide placeholder:text-center border-0 block w-full pt-0.5 pb-0.5 form-input dark:bg-gray-900 dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm sm:text-sm focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200"
|
||||||
|
: "block w-full form-input dark:bg-gray-900 arrow-hide dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
||||||
(disabled ? " bg-gray-200 dark:bg-gray-700" : "")
|
(disabled ? " bg-gray-200 dark:bg-gray-700" : "")
|
||||||
}
|
}
|
||||||
placeholder="Type a number from zero to one"
|
placeholder={
|
||||||
|
editNode ? "Number 0 to 1" : "Type a number from zero to one"
|
||||||
|
}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setMyValue(e.target.value);
|
setMyValue(e.target.value);
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ export default function InputComponent({
|
||||||
disableCopyPaste = false,
|
disableCopyPaste = false,
|
||||||
disabled,
|
disabled,
|
||||||
password,
|
password,
|
||||||
|
editNode = false,
|
||||||
}: InputComponentType) {
|
}: InputComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value ?? "");
|
const [myValue, setMyValue] = useState(value ?? "");
|
||||||
const [pwdVisible, setPwdVisible] = useState(false);
|
const [pwdVisible, setPwdVisible] = useState(false);
|
||||||
|
|
@ -19,6 +20,7 @@ export default function InputComponent({
|
||||||
onChange("");
|
onChange("");
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled, onChange]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
|
|
@ -36,18 +38,27 @@ export default function InputComponent({
|
||||||
if (disableCopyPaste) setDisableCopyPaste(false);
|
if (disableCopyPaste) setDisableCopyPaste(false);
|
||||||
}}
|
}}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"block w-full pr-12 form-input dark:bg-gray-900 dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm",
|
"block w-full pr-12 form-input dark:bg-gray-900 dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm sm:text-sm",
|
||||||
disabled ? " bg-gray-200 dark:bg-gray-700" : "",
|
disabled ? " bg-gray-200 dark:bg-gray-700" : "",
|
||||||
password && !pwdVisible && myValue !== "" ? "password" : ""
|
password && !pwdVisible && myValue !== "" ? "password" : "",
|
||||||
|
editNode
|
||||||
|
? "placeholder:text-center border-0 block w-full pt-0.5 pb-0.5 form-input dark:bg-gray-900 dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm sm:text-sm focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200 text-center"
|
||||||
|
: "focus:border-indigo-500 focus:ring-indigo-500",
|
||||||
|
password && editNode ? "pr-8" : "pr-3"
|
||||||
)}
|
)}
|
||||||
placeholder="Type something..."
|
placeholder={password && editNode ? "Key" : "Type something..."}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setMyValue(e.target.value);
|
setMyValue(e.target.value);
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{password && (
|
||||||
<button
|
<button
|
||||||
className="absolute inset-y-0 right-0 items-center px-4 text-gray-600"
|
className={classNames(
|
||||||
|
editNode
|
||||||
|
? "absolute inset-y-0 right-0 pr-2 items-center text-gray-600"
|
||||||
|
: "absolute inset-y-0 right-0 items-center px-4 text-gray-600"
|
||||||
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setPwdVisible(!pwdVisible);
|
setPwdVisible(!pwdVisible);
|
||||||
}}
|
}}
|
||||||
|
|
@ -90,6 +101,7 @@ export default function InputComponent({
|
||||||
</svg>
|
</svg>
|
||||||
))}
|
))}
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ export default function InputFileComponent({
|
||||||
suffixes,
|
suffixes,
|
||||||
fileTypes,
|
fileTypes,
|
||||||
onFileChange,
|
onFileChange,
|
||||||
|
editNode = false,
|
||||||
}: FileComponentType) {
|
}: FileComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value);
|
const [myValue, setMyValue] = useState(value);
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
|
|
@ -71,14 +72,18 @@ export default function InputFileComponent({
|
||||||
<span
|
<span
|
||||||
onClick={handleButtonClick}
|
onClick={handleButtonClick}
|
||||||
className={
|
className={
|
||||||
"truncate block w-full text-gray-500 dark:text-gray-300 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
editNode
|
||||||
|
? "placeholder:text-center text-gray-500 border-0 block w-full pt-0.5 pb-0.5 form-input dark:bg-gray-900 dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm sm:text-sm focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200"
|
||||||
|
: "truncate block w-full text-gray-500 dark:text-gray-300 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
||||||
(disabled ? " bg-gray-200" : "")
|
(disabled ? " bg-gray-200" : "")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{myValue !== "" ? myValue : "No file"}
|
{myValue !== "" ? myValue : "No file"}
|
||||||
</span>
|
</span>
|
||||||
<button onClick={handleButtonClick}>
|
<button onClick={handleButtonClick}>
|
||||||
|
{!editNode && (
|
||||||
<DocumentMagnifyingGlassIcon className="w-8 h-8 hover:text-blue-600" />
|
<DocumentMagnifyingGlassIcon className="w-8 h-8 hover:text-blue-600" />
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useContext, useEffect, useState } from "react";
|
||||||
import { FloatComponentType } from "../../types/components";
|
import { FloatComponentType } from "../../types/components";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
|
import { classNames } from "../../utils";
|
||||||
|
|
||||||
export default function IntComponent({
|
export default function IntComponent({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
disableCopyPaste = false,
|
disableCopyPaste = false,
|
||||||
disabled,
|
disabled,
|
||||||
|
editNode = false,
|
||||||
}: FloatComponentType) {
|
}: FloatComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value ?? "");
|
const [myValue, setMyValue] = useState(value ?? "");
|
||||||
const { setDisableCopyPaste } = useContext(TabsContext);
|
const { setDisableCopyPaste } = useContext(TabsContext);
|
||||||
|
|
@ -53,10 +55,12 @@ export default function IntComponent({
|
||||||
type="number"
|
type="number"
|
||||||
value={myValue}
|
value={myValue}
|
||||||
className={
|
className={
|
||||||
"block w-full form-input dark:bg-gray-900 arrow-hide dark:border-gray-600 dark:text-gray-300 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
editNode
|
||||||
|
? "text-center arrow-hide placeholder:text-center border-0 block w-full pt-0.5 pb-0.5 form-input dark:bg-gray-900 dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm sm:text-sm focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200"
|
||||||
|
: "block w-full form-input dark:bg-gray-900 arrow-hide dark:border-gray-600 dark:text-gray-300 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
||||||
(disabled ? " bg-gray-200 dark:bg-gray-700" : "")
|
(disabled ? " bg-gray-200 dark:bg-gray-700" : "")
|
||||||
}
|
}
|
||||||
placeholder="Type a integer number"
|
placeholder={editNode ? "Integer number" : "Type a integer number"}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setMyValue(e.target.value);
|
setMyValue(e.target.value);
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ export default function PromptAreaComponent({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
disabled,
|
disabled,
|
||||||
|
editNode = false,
|
||||||
}: TextAreaComponentType) {
|
}: TextAreaComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value);
|
const [myValue, setMyValue] = useState(value);
|
||||||
const { openPopUp } = useContext(PopUpContext);
|
const { openPopUp } = useContext(PopUpContext);
|
||||||
|
|
@ -43,11 +44,13 @@ export default function PromptAreaComponent({
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
"truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
editNode
|
||||||
|
? "h-7 truncate placeholder:text-center text-gray-500 border-0 block w-full pt-0.5 pb-0.5 form-input dark:bg-gray-900 dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm sm:text-sm focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200"
|
||||||
|
: "truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
||||||
(disabled ? " bg-gray-200" : "")
|
(disabled ? " bg-gray-200" : "")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{myValue !== "" ? myValue : "Text empty"}
|
{myValue !== "" ? myValue : "-"}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -65,7 +68,9 @@ export default function PromptAreaComponent({
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{!editNode && (
|
||||||
<ArrowTopRightOnSquareIcon className="w-6 h-6 hover:text-blue-600 dark:text-gray-300" />
|
<ArrowTopRightOnSquareIcon className="w-6 h-6 hover:text-blue-600 dark:text-gray-300" />
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ export default function TextAreaComponent({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
disabled,
|
disabled,
|
||||||
|
editNode = false,
|
||||||
}: TextAreaComponentType) {
|
}: TextAreaComponentType) {
|
||||||
const [myValue, setMyValue] = useState(value);
|
const [myValue, setMyValue] = useState(value);
|
||||||
const { openPopUp } = useContext(PopUpContext);
|
const { openPopUp } = useContext(PopUpContext);
|
||||||
|
|
@ -37,7 +38,9 @@ export default function TextAreaComponent({
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
"truncate block w-full text-gray-500 dark:text-gray-100 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
editNode
|
||||||
|
? "h-7 truncate placeholder:text-center text-gray-500 border-0 block w-full pt-0.5 pb-0.5 form-input dark:bg-gray-900 dark:text-gray-300 dark:border-gray-600 rounded-md border-gray-300 shadow-sm sm:text-sm focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200"
|
||||||
|
: "truncate block w-full text-gray-500 dark:text-gray-100 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
||||||
(disabled ? " bg-gray-200" : "")
|
(disabled ? " bg-gray-200" : "")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -59,7 +62,9 @@ export default function TextAreaComponent({
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{!editNode && (
|
||||||
<ArrowTopRightOnSquareIcon className="w-6 h-6 hover:text-blue-600 dark:text-gray-300" />
|
<ArrowTopRightOnSquareIcon className="w-6 h-6 hover:text-blue-600 dark:text-gray-300" />
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
29
src/frontend/src/components/toggleShadComponent/index.tsx
Normal file
29
src/frontend/src/components/toggleShadComponent/index.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { classNames } from "../../utils";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { ToggleComponentType } from "../../types/components";
|
||||||
|
import { Switch } from "../ui/switch";
|
||||||
|
|
||||||
|
export default function ToggleShadComponent({
|
||||||
|
enabled,
|
||||||
|
setEnabled,
|
||||||
|
disabled,
|
||||||
|
}: ToggleComponentType) {
|
||||||
|
useEffect(() => {
|
||||||
|
if (disabled) {
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
}, [disabled, setEnabled]);
|
||||||
|
return (
|
||||||
|
<div className={disabled ? "pointer-events-none cursor-not-allowed" : ""}>
|
||||||
|
<Switch
|
||||||
|
style={{
|
||||||
|
transform: "scaleX(0.6) scaleY(0.6)",
|
||||||
|
}}
|
||||||
|
checked={enabled}
|
||||||
|
onCheckedChange={(x: boolean) => {
|
||||||
|
setEnabled(x);
|
||||||
|
}}
|
||||||
|
></Switch>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
54
src/frontend/src/components/ui/button.tsx
Normal file
54
src/frontend/src/components/ui/button.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
import { cn } from "../../utils";
|
||||||
|
|
||||||
|
const buttonVariants = cva(
|
||||||
|
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||||
|
destructive:
|
||||||
|
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||||
|
outline:
|
||||||
|
"border border-input hover:bg-accent hover:text-accent-foreground",
|
||||||
|
secondary:
|
||||||
|
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||||
|
link: "underline-offset-4 hover:underline text-primary",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: "h-10 py-2 px-4",
|
||||||
|
sm: "h-9 px-3 rounded-md",
|
||||||
|
lg: "h-11 px-8 rounded-md",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface ButtonProps
|
||||||
|
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
|
VariantProps<typeof buttonVariants> {
|
||||||
|
asChild?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||||
|
const Comp = asChild ? Slot : "button";
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Button.displayName = "Button";
|
||||||
|
|
||||||
|
export { Button, buttonVariants };
|
||||||
29
src/frontend/src/components/ui/checkbox.tsx
Normal file
29
src/frontend/src/components/ui/checkbox.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
||||||
|
import { Check } from "lucide-react";
|
||||||
|
import { cn } from "../../utils";
|
||||||
|
|
||||||
|
const Checkbox = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CheckboxPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<CheckboxPrimitive.Indicator
|
||||||
|
className={cn("flex items-center justify-center text-current")}
|
||||||
|
>
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
</CheckboxPrimitive.Indicator>
|
||||||
|
</CheckboxPrimitive.Root>
|
||||||
|
));
|
||||||
|
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
||||||
|
|
||||||
|
export { Checkbox };
|
||||||
125
src/frontend/src/components/ui/dialog.tsx
Normal file
125
src/frontend/src/components/ui/dialog.tsx
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||||
|
import { X } from "lucide-react";
|
||||||
|
import { cn } from "../../utils";
|
||||||
|
|
||||||
|
const Dialog = DialogPrimitive.Root;
|
||||||
|
|
||||||
|
const DialogTrigger = DialogPrimitive.Trigger;
|
||||||
|
|
||||||
|
const DialogPortal = ({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: DialogPrimitive.DialogPortalProps) => (
|
||||||
|
<DialogPrimitive.Portal className={cn(className)} {...props}>
|
||||||
|
<div className="fixed inset-0 z-50 flex items-start justify-center sm:items-center">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</DialogPrimitive.Portal>
|
||||||
|
);
|
||||||
|
DialogPortal.displayName = DialogPrimitive.Portal.displayName;
|
||||||
|
|
||||||
|
const DialogOverlay = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DialogPrimitive.Overlay
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
|
const DialogContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<DialogPortal>
|
||||||
|
<DialogOverlay />
|
||||||
|
<DialogPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"fixed z-50 grid w-full gap-4 rounded-b-lg border bg-background p-6 shadow-lg animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||||
|
<X className="h-4 w-4" />
|
||||||
|
<span className="sr-only">Close</span>
|
||||||
|
</DialogPrimitive.Close>
|
||||||
|
</DialogPrimitive.Content>
|
||||||
|
</DialogPortal>
|
||||||
|
));
|
||||||
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||||
|
|
||||||
|
const DialogHeader = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
DialogHeader.displayName = "DialogHeader";
|
||||||
|
|
||||||
|
const DialogFooter = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
DialogFooter.displayName = "DialogFooter";
|
||||||
|
|
||||||
|
const DialogTitle = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DialogPrimitive.Title
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"text-lg font-semibold leading-none tracking-tight",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||||
|
|
||||||
|
const DialogDescription = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DialogPrimitive.Description
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Dialog,
|
||||||
|
DialogTrigger,
|
||||||
|
DialogContent,
|
||||||
|
DialogHeader,
|
||||||
|
DialogFooter,
|
||||||
|
DialogTitle,
|
||||||
|
DialogDescription,
|
||||||
|
};
|
||||||
24
src/frontend/src/components/ui/input.tsx
Normal file
24
src/frontend/src/components/ui/input.tsx
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { cn } from "../../utils";
|
||||||
|
|
||||||
|
export interface InputProps
|
||||||
|
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||||
|
|
||||||
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
|
({ className, type, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type={type}
|
||||||
|
className={cn(
|
||||||
|
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Input.displayName = "Input";
|
||||||
|
|
||||||
|
export { Input };
|
||||||
25
src/frontend/src/components/ui/label.tsx
Normal file
25
src/frontend/src/components/ui/label.tsx
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
import { cn } from "../../utils";
|
||||||
|
|
||||||
|
const labelVariants = cva(
|
||||||
|
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||||
|
);
|
||||||
|
|
||||||
|
const Label = React.forwardRef<
|
||||||
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||||
|
VariantProps<typeof labelVariants>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<LabelPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn(labelVariants(), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
Label.displayName = LabelPrimitive.Root.displayName;
|
||||||
|
|
||||||
|
export { Label };
|
||||||
28
src/frontend/src/components/ui/switch.tsx
Normal file
28
src/frontend/src/components/ui/switch.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
||||||
|
import { cn } from "../../utils";
|
||||||
|
|
||||||
|
const Switch = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SwitchPrimitives.Root
|
||||||
|
className={cn(
|
||||||
|
"peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
>
|
||||||
|
<SwitchPrimitives.Thumb
|
||||||
|
className={cn(
|
||||||
|
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SwitchPrimitives.Root>
|
||||||
|
));
|
||||||
|
Switch.displayName = SwitchPrimitives.Root.displayName;
|
||||||
|
|
||||||
|
export { Switch };
|
||||||
113
src/frontend/src/components/ui/table.tsx
Normal file
113
src/frontend/src/components/ui/table.tsx
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { cn } from "../../utils";
|
||||||
|
|
||||||
|
const Table = React.forwardRef<
|
||||||
|
HTMLTableElement,
|
||||||
|
React.HTMLAttributes<HTMLTableElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<div className="w-full overflow-auto">
|
||||||
|
<table
|
||||||
|
ref={ref}
|
||||||
|
className={cn("w-full caption-bottom text-sm", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
Table.displayName = "Table";
|
||||||
|
|
||||||
|
const TableHeader = React.forwardRef<
|
||||||
|
HTMLTableSectionElement,
|
||||||
|
React.HTMLAttributes<HTMLTableSectionElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
||||||
|
));
|
||||||
|
TableHeader.displayName = "TableHeader";
|
||||||
|
|
||||||
|
const TableBody = React.forwardRef<
|
||||||
|
HTMLTableSectionElement,
|
||||||
|
React.HTMLAttributes<HTMLTableSectionElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<tbody
|
||||||
|
ref={ref}
|
||||||
|
className={cn("[&_tr:last-child]:border-0", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
TableBody.displayName = "TableBody";
|
||||||
|
|
||||||
|
const TableFooter = React.forwardRef<
|
||||||
|
HTMLTableSectionElement,
|
||||||
|
React.HTMLAttributes<HTMLTableSectionElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<tfoot
|
||||||
|
ref={ref}
|
||||||
|
className={cn("bg-primary font-medium text-primary-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
TableFooter.displayName = "TableFooter";
|
||||||
|
|
||||||
|
const TableRow = React.forwardRef<
|
||||||
|
HTMLTableRowElement,
|
||||||
|
React.HTMLAttributes<HTMLTableRowElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<tr
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
TableRow.displayName = "TableRow";
|
||||||
|
|
||||||
|
const TableHead = React.forwardRef<
|
||||||
|
HTMLTableCellElement,
|
||||||
|
React.ThHTMLAttributes<HTMLTableCellElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<th
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
TableHead.displayName = "TableHead";
|
||||||
|
|
||||||
|
const TableCell = React.forwardRef<
|
||||||
|
HTMLTableCellElement,
|
||||||
|
React.TdHTMLAttributes<HTMLTableCellElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<td
|
||||||
|
ref={ref}
|
||||||
|
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
TableCell.displayName = "TableCell";
|
||||||
|
|
||||||
|
const TableCaption = React.forwardRef<
|
||||||
|
HTMLTableCaptionElement,
|
||||||
|
React.HTMLAttributes<HTMLTableCaptionElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<caption
|
||||||
|
ref={ref}
|
||||||
|
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
TableCaption.displayName = "TableCaption";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Table,
|
||||||
|
TableHeader,
|
||||||
|
TableBody,
|
||||||
|
TableFooter,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
TableCell,
|
||||||
|
TableCaption,
|
||||||
|
};
|
||||||
23
src/frontend/src/components/ui/textarea.tsx
Normal file
23
src/frontend/src/components/ui/textarea.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { cn } from "../../utils";
|
||||||
|
|
||||||
|
export interface TextareaProps
|
||||||
|
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||||
|
|
||||||
|
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||||
|
({ className, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<textarea
|
||||||
|
className={cn(
|
||||||
|
"flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Textarea.displayName = "Textarea";
|
||||||
|
|
||||||
|
export { Textarea };
|
||||||
39
src/frontend/src/constants.tsx
Normal file
39
src/frontend/src/constants.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
// src/constants.tsx
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base text for subtitle of Export Dialog (Toolbar)
|
||||||
|
* @constant
|
||||||
|
*/
|
||||||
|
export const EXPORT_DIALOG_SUBTITLE = "Export your models.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base text for subtitle of Code Dialog (Toolbar)
|
||||||
|
* @constant
|
||||||
|
*/
|
||||||
|
export const CODE_DIALOG_SUBTITLE =
|
||||||
|
"Export your flow to use it with this code.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base text for subtitle of Edit Node Dialog
|
||||||
|
* @constant
|
||||||
|
*/
|
||||||
|
export const EDIT_DIALOG_SUBTITLE =
|
||||||
|
"Make configurations changes to your nodes. Click save when you're done.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base text for subtitle of Code Dialog
|
||||||
|
* @constant
|
||||||
|
*/
|
||||||
|
export const CODE_PROMPT_DIALOG_SUBTITLE = "Edit you python code.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base text for subtitle of Prompt Dialog
|
||||||
|
* @constant
|
||||||
|
*/
|
||||||
|
export const PROMPT_DIALOG_SUBTITLE = "Edit you prompt.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base text for subtitle of Text Dialog
|
||||||
|
* @constant
|
||||||
|
*/
|
||||||
|
export const TEXT_DIALOG_SUBTITLE = "Edit you text.";
|
||||||
|
|
@ -35,10 +35,13 @@ const TabsContextInitialValue: TabsContextType = {
|
||||||
hardReset: () => {},
|
hardReset: () => {},
|
||||||
disableCopyPaste: false,
|
disableCopyPaste: false,
|
||||||
setDisableCopyPaste: (state: boolean) => {},
|
setDisableCopyPaste: (state: boolean) => {},
|
||||||
|
lastCopiedSelection: null,
|
||||||
|
setLastCopiedSelection: (selection: any) => {},
|
||||||
|
|
||||||
getNodeId: () => "",
|
getNodeId: () => "",
|
||||||
paste: (
|
paste: (
|
||||||
selection: { nodes: any; edges: any },
|
selection: { nodes: any; edges: any },
|
||||||
position: { x: number; y: number }
|
position: { x: number; y: number; paneX?: number; paneY?: number }
|
||||||
) => {},
|
) => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -52,6 +55,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
const [flows, setFlows] = useState<Array<FlowType>>([]);
|
const [flows, setFlows] = useState<Array<FlowType>>([]);
|
||||||
const [id, setId] = useState(uuidv4());
|
const [id, setId] = useState(uuidv4());
|
||||||
const { templates, reactFlowInstance } = useContext(typesContext);
|
const { templates, reactFlowInstance } = useContext(typesContext);
|
||||||
|
const [lastCopiedSelection, setLastCopiedSelection] = useState(null);
|
||||||
|
|
||||||
const newNodeId = useRef(uuidv4());
|
const newNodeId = useRef(uuidv4());
|
||||||
function incrementNodeId() {
|
function incrementNodeId() {
|
||||||
|
|
@ -163,7 +167,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
// simulate a click on the link element to trigger the download
|
// simulate a click on the link element to trigger the download
|
||||||
link.click();
|
link.click();
|
||||||
setNoticeData({
|
setNoticeData({
|
||||||
title: "Warning: Critical data,JSON file may including API keys.",
|
title: "Warning: Critical data, JSON file may include API keys.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,7 +229,10 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
* @param flow Optional flow to add.
|
* @param flow Optional flow to add.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function paste(selectionInstance, position) {
|
function paste(
|
||||||
|
selectionInstance,
|
||||||
|
position: { x: number; y: number; paneX?: number; paneY?: number }
|
||||||
|
) {
|
||||||
let minimumX = Infinity;
|
let minimumX = Infinity;
|
||||||
let minimumY = Infinity;
|
let minimumY = Infinity;
|
||||||
let idsMap = {};
|
let idsMap = {};
|
||||||
|
|
@ -240,7 +247,9 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const insidePosition = reactFlowInstance.project(position);
|
const insidePosition = position.paneX
|
||||||
|
? { x: position.paneX + position.x, y: position.paneY + position.y }
|
||||||
|
: reactFlowInstance.project({ x: position.x, y: position.y });
|
||||||
|
|
||||||
selectionInstance.nodes.forEach((n) => {
|
selectionInstance.nodes.forEach((n) => {
|
||||||
// Generate a unique node ID
|
// Generate a unique node ID
|
||||||
|
|
@ -391,6 +400,8 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<TabsContext.Provider
|
<TabsContext.Provider
|
||||||
value={{
|
value={{
|
||||||
|
lastCopiedSelection,
|
||||||
|
setLastCopiedSelection,
|
||||||
disableCopyPaste,
|
disableCopyPaste,
|
||||||
setDisableCopyPaste,
|
setDisableCopyPaste,
|
||||||
save,
|
save,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,73 @@
|
||||||
:root {
|
:root {
|
||||||
--background: 0 0% 100%;
|
--background: 0 0% 100%;
|
||||||
--foreground: 222.2 47.4% 11.2%;
|
--foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--muted: 210 40% 96.1%;
|
||||||
|
--muted-foreground: 215.4 16.3% 46.9%;
|
||||||
|
|
||||||
|
--popover: 0 0% 100%;
|
||||||
|
--popover-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--card: 0 0% 100%;
|
||||||
|
--card-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--border: 214.3 31.8% 91.4%;
|
||||||
|
--input: 214.3 31.8% 91.4%;
|
||||||
|
|
||||||
|
--primary: 222.2 47.4% 11.2%;
|
||||||
|
--primary-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--secondary: 210 40% 96.1%;
|
||||||
|
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--accent: 210 40% 96.1%;
|
||||||
|
--accent-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--destructive: 0 100% 50%;
|
||||||
|
--destructive-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--ring: 215 20.2% 65.1%;
|
||||||
|
|
||||||
|
--radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
--background: 224 71% 4%;
|
||||||
|
--foreground: 213 31% 91%;
|
||||||
|
|
||||||
|
--muted: 223 47% 11%;
|
||||||
|
--muted-foreground: 215.4 16.3% 56.9%;
|
||||||
|
|
||||||
|
--popover: 224 71% 4%;
|
||||||
|
--popover-foreground: 215 20.2% 65.1%;
|
||||||
|
|
||||||
|
--card: 224 71% 4%;
|
||||||
|
--card-foreground: 213 31% 91%;
|
||||||
|
|
||||||
|
--border: 216 34% 17%;
|
||||||
|
--input: 216 34% 17%;
|
||||||
|
|
||||||
|
--primary: 210 40% 98%;
|
||||||
|
--primary-foreground: 222.2 47.4% 1.2%;
|
||||||
|
|
||||||
|
--secondary: 222.2 47.4% 11.2%;
|
||||||
|
--secondary-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--accent: 216 34% 17%;
|
||||||
|
--accent-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--destructive: 0 63% 31%;
|
||||||
|
--destructive-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--ring: 216 34% 17%;
|
||||||
|
|
||||||
|
--radius: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background: 0 0% 100%;
|
||||||
|
--foreground: 222.2 47.4% 11.2%;
|
||||||
--muted: 210 40% 96.1%;
|
--muted: 210 40% 96.1%;
|
||||||
--muted-foreground: 215.4 16.3% 46.9%;
|
--muted-foreground: 215.4 16.3% 46.9%;
|
||||||
--popover: 0 0% 100%;
|
--popover: 0 0% 100%;
|
||||||
|
|
@ -24,9 +91,9 @@
|
||||||
--destructive-foreground: 210 40% 98%;
|
--destructive-foreground: 210 40% 98%;
|
||||||
--ring: 215 20.2% 65.1%;
|
--ring: 215 20.2% 65.1%;
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
-background: 224 71% 4%;
|
-background: 224 71% 4%;
|
||||||
-foreground: 213 31% 91%;
|
-foreground: 213 31% 91%;
|
||||||
-muted: 223 47% 11%;
|
-muted: 223 47% 11%;
|
||||||
|
|
@ -47,23 +114,13 @@
|
||||||
-destructive-foreground: 210 40% 98%;
|
-destructive-foreground: 210 40% 98%;
|
||||||
-ring: 216 34% 17%;
|
-ring: 216 34% 17%;
|
||||||
-radius: 0.5rem;
|
-radius: 0.5rem;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer base {
|
|
||||||
* {
|
|
||||||
@apply border-border;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
@apply bg-background text-foreground;
|
|
||||||
font-feature-settings: "rlig" 1, "calt" 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
* {
|
* {
|
||||||
@apply border-border;
|
@apply border-border;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground;
|
||||||
font-feature-settings: "rlig" 1, "calt" 1;
|
font-feature-settings: "rlig" 1, "calt" 1;
|
||||||
|
|
@ -84,6 +141,8 @@ code {
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The style below sets the cursor property of the element with the class .react-flow__pane to the default cursor.
|
||||||
|
The cursor: default; property value restores the browser's default cursor style for the targeted element. By applying this style, the element will no longer have a custom cursor appearance such as "grab" or any other custom cursor defined elsewhere in the application. Instead, it will revert to the default cursor style determined by the browser, typically an arrow-shaped cursor. */
|
||||||
.react-flow__pane {
|
.react-flow__pane {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
|
||||||
import { IconCheck, IconClipboard, IconDownload } from "@tabler/icons-react";
|
import { IconCheck, IconClipboard, IconDownload } from "@tabler/icons-react";
|
||||||
import {
|
import {
|
||||||
XMarkIcon,
|
XMarkIcon,
|
||||||
|
|
@ -15,13 +14,22 @@ import "ace-builds/src-noconflict/ext-language_tools";
|
||||||
import { darkContext } from "../../contexts/darkContext";
|
import { darkContext } from "../../contexts/darkContext";
|
||||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||||
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "../../components/ui/dialog";
|
||||||
|
import { Button } from "../../components/ui/button";
|
||||||
|
|
||||||
export default function ApiModal({ flowName }) {
|
export default function ApiModal({ flowName }) {
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
const { dark } = useContext(darkContext);
|
const { dark } = useContext(darkContext);
|
||||||
const { closePopUp } = useContext(PopUpContext);
|
const { closePopUp } = useContext(PopUpContext);
|
||||||
const [activeTab, setActiveTab] = useState(0);
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
const ref = useRef();
|
|
||||||
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
||||||
|
|
||||||
const copyToClipboard = () => {
|
const copyToClipboard = () => {
|
||||||
|
|
@ -40,9 +48,7 @@ export default function ApiModal({ flowName }) {
|
||||||
function setModalOpen(x: boolean) {
|
function setModalOpen(x: boolean) {
|
||||||
setOpen(x);
|
setOpen(x);
|
||||||
if (x === false) {
|
if (x === false) {
|
||||||
setTimeout(() => {
|
|
||||||
closePopUp();
|
closePopUp();
|
||||||
}, 300);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,71 +88,27 @@ flow("Hey, have you heard of LangFlow?")`;
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={open} appear={true} as={Fragment}>
|
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||||
<Dialog
|
<DialogTrigger></DialogTrigger>
|
||||||
as="div"
|
<DialogContent className="lg:max-w-[800px] sm:max-w-[600px] h-[550px]">
|
||||||
className="relative z-10"
|
<DialogHeader>
|
||||||
onClose={setModalOpen}
|
<DialogTitle className="flex items-center">
|
||||||
initialFocus={ref}
|
<span className="pr-2">Code</span>
|
||||||
>
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0"
|
|
||||||
enterTo="opacity-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100"
|
|
||||||
leaveTo="opacity-0"
|
|
||||||
>
|
|
||||||
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
|
|
||||||
</Transition.Child>
|
|
||||||
|
|
||||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
|
||||||
<div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
>
|
|
||||||
<Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]">
|
|
||||||
<div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="rounded-md text-gray-400 hover:text-gray-500"
|
|
||||||
onClick={() => {
|
|
||||||
setModalOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="sr-only">Close</span>
|
|
||||||
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="h-full w-full flex flex-col justify-center items-center">
|
|
||||||
<div className="flex w-full pb-4 z-10 justify-center shadow-sm">
|
|
||||||
<div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10">
|
|
||||||
<CodeBracketSquareIcon
|
<CodeBracketSquareIcon
|
||||||
className="h-6 w-6 text-blue-600"
|
className="h-6 w-6 text-gray-800 pl-1 dark:text-white"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</DialogTitle>
|
||||||
<div className="mt-4 text-center sm:ml-4 sm:text-left">
|
<DialogDescription>
|
||||||
<Dialog.Title
|
Export your flow to use it with this code.
|
||||||
as="h3"
|
</DialogDescription>
|
||||||
className="text-lg font-medium dark:text-white leading-10 text-gray-900"
|
</DialogHeader>
|
||||||
>
|
|
||||||
Code
|
|
||||||
</Dialog.Title>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="h-full w-full bg-gray-200 overflow-auto dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center">
|
|
||||||
<div className="flex flex-col h-full w-full ">
|
<div className="flex flex-col h-full w-full ">
|
||||||
<div className="flex px-5 z-10">
|
<div className="flex px-5 z-10">
|
||||||
{tabs.map((tab, index) => (
|
{tabs.map((tab, index) => (
|
||||||
<button
|
<button
|
||||||
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActiveTab(index);
|
setActiveTab(index);
|
||||||
}}
|
}}
|
||||||
|
|
@ -162,11 +124,9 @@ flow("Hey, have you heard of LangFlow?")`;
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="overflow-hidden px-4 py-5 sm:p-6 w-full h-full rounded-lg shadow bg-white dark:bg-gray-800">
|
<div className="overflow-hidden px-4 sm:p-4 sm:pb-0 sm:pt-0 w-full h-full rounded-lg shadow bg-white dark:bg-gray-800">
|
||||||
<div className="w-full flex items-center justify-between mb-2">
|
<div className="items-center mb-2">
|
||||||
<span className="text-sm text-gray-500 dark:text-gray-300">
|
<div className="float-right">
|
||||||
Export your flow to use it with this code.
|
|
||||||
</span>
|
|
||||||
<button
|
<button
|
||||||
className="flex gap-1.5 items-center rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
|
className="flex gap-1.5 items-center rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
|
||||||
onClick={copyToClipboard}
|
onClick={copyToClipboard}
|
||||||
|
|
@ -179,8 +139,9 @@ flow("Hey, have you heard of LangFlow?")`;
|
||||||
{isCopied ? "Copied!" : "Copy code"}
|
{isCopied ? "Copied!" : "Copy code"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<SyntaxHighlighter
|
<SyntaxHighlighter
|
||||||
className="h-[370px]"
|
className="h-[370px] w-full"
|
||||||
language={tabs[activeTab].mode}
|
language={tabs[activeTab].mode}
|
||||||
style={oneDark}
|
style={oneDark}
|
||||||
customStyle={{ margin: 0 }}
|
customStyle={{ margin: 0 }}
|
||||||
|
|
@ -189,13 +150,7 @@ flow("Hey, have you heard of LangFlow?")`;
|
||||||
</SyntaxHighlighter>
|
</SyntaxHighlighter>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</DialogContent>
|
||||||
</div>
|
|
||||||
</Dialog.Panel>
|
|
||||||
</Transition.Child>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
335
src/frontend/src/modals/EditNodeModal/index.tsx
Normal file
335
src/frontend/src/modals/EditNodeModal/index.tsx
Normal file
|
|
@ -0,0 +1,335 @@
|
||||||
|
import {
|
||||||
|
ChevronDoubleLeftIcon,
|
||||||
|
ChevronDoubleRightIcon,
|
||||||
|
PencilSquareIcon,
|
||||||
|
XMarkIcon,
|
||||||
|
} from "@heroicons/react/24/outline";
|
||||||
|
import { Fragment, useContext, useEffect, useRef, useState } from "react";
|
||||||
|
import { PopUpContext } from "../../contexts/popUpContext";
|
||||||
|
import { NodeDataType } from "../../types/flow";
|
||||||
|
import { classNames, limitScrollFieldsModal, nodeIcons } from "../../utils";
|
||||||
|
import { typesContext } from "../../contexts/typesContext";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "../../components/ui/table";
|
||||||
|
import { Switch } from "../../components/ui/switch";
|
||||||
|
import ToggleShadComponent from "../../components/toggleShadComponent";
|
||||||
|
import { VariableIcon } from "@heroicons/react/24/outline";
|
||||||
|
import InputListComponent from "../../components/inputListComponent";
|
||||||
|
import TextAreaComponent from "../../components/textAreaComponent";
|
||||||
|
import InputComponent from "../../components/inputComponent";
|
||||||
|
import ToggleComponent from "../../components/toggleComponent";
|
||||||
|
import FloatComponent from "../../components/floatComponent";
|
||||||
|
import Dropdown from "../../components/dropdownComponent";
|
||||||
|
import IntComponent from "../../components/intComponent";
|
||||||
|
import InputFileComponent from "../../components/inputFileComponent";
|
||||||
|
import PromptAreaComponent from "../../components/promptComponent";
|
||||||
|
import CodeAreaComponent from "../../components/codeAreaComponent";
|
||||||
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "../../components/ui/dialog";
|
||||||
|
import { Button } from "../../components/ui/button";
|
||||||
|
import { EDIT_DIALOG_SUBTITLE } from "../../constants";
|
||||||
|
|
||||||
|
export default function EditNodeModal({ data }: { data: NodeDataType }) {
|
||||||
|
const [open, setOpen] = useState(true);
|
||||||
|
const [nodeLength, setNodeLength] = useState(
|
||||||
|
Object.keys(data.node.template).filter(
|
||||||
|
(t) =>
|
||||||
|
t.charAt(0) !== "_" &&
|
||||||
|
data.node.template[t].show &&
|
||||||
|
(data.node.template[t].type === "str" ||
|
||||||
|
data.node.template[t].type === "bool" ||
|
||||||
|
data.node.template[t].type === "float" ||
|
||||||
|
data.node.template[t].type === "code" ||
|
||||||
|
data.node.template[t].type === "prompt" ||
|
||||||
|
data.node.template[t].type === "file" ||
|
||||||
|
data.node.template[t].type === "int")
|
||||||
|
).length
|
||||||
|
);
|
||||||
|
const [nodeValue, setNodeValue] = useState(true);
|
||||||
|
const { closePopUp } = useContext(PopUpContext);
|
||||||
|
const { types } = useContext(typesContext);
|
||||||
|
const ref = useRef();
|
||||||
|
const { save } = useContext(TabsContext);
|
||||||
|
const [enabled, setEnabled] = useState(false);
|
||||||
|
if (nodeLength == 0) {
|
||||||
|
closePopUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setModalOpen(x: boolean) {
|
||||||
|
setOpen(x);
|
||||||
|
if (x === false) {
|
||||||
|
closePopUp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeAdvanced(node): void {
|
||||||
|
Object.keys(data.node.template).filter((n, i) => {
|
||||||
|
if (n === node.name) {
|
||||||
|
data.node.template[n].advanced = !data.node.template[n].advanced;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
setNodeValue(!nodeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(data.node.template);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||||
|
<DialogTrigger></DialogTrigger>
|
||||||
|
<DialogContent className="lg:max-w-[700px]">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle className="flex items-center">
|
||||||
|
<span className="pr-2">Edit Node</span>
|
||||||
|
<PencilSquareIcon
|
||||||
|
className="h-6 w-6 text-gray-800 pl-1 dark:text-white"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
{EDIT_DIALOG_SUBTITLE}
|
||||||
|
<div className="flex pt-3">
|
||||||
|
<VariableIcon className="w-5 h-5 pe-1 text-gray-700 stroke-2">
|
||||||
|
|
||||||
|
</VariableIcon>
|
||||||
|
<span className="text-sm font-semibold text-gray-800">
|
||||||
|
Parameters
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="flex w-full h-fit max-h-[415px]">
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"w-full rounded-lg bg-white dark:bg-gray-800 shadow",
|
||||||
|
nodeLength > limitScrollFieldsModal
|
||||||
|
? "overflow-scroll overflow-x-hidden custom-scroll"
|
||||||
|
: "overflow-hidden"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{nodeLength > 0 && (
|
||||||
|
<div className="flex flex-col gap-5 h-fit">
|
||||||
|
<Table className="table-fixed">
|
||||||
|
<TableHeader className="border-gray-200 text-gray-500 text-xs font-medium">
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="h-7 text-center">PARAM</TableHead>
|
||||||
|
<TableHead className="p-0 h-7 text-center">
|
||||||
|
VALUE
|
||||||
|
</TableHead>
|
||||||
|
<TableHead className="text-center h-7">SHOW</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody className="p-0">
|
||||||
|
{Object.keys(data.node.template)
|
||||||
|
.filter(
|
||||||
|
(t) =>
|
||||||
|
t.charAt(0) !== "_" &&
|
||||||
|
data.node.template[t].show &&
|
||||||
|
(data.node.template[t].type === "str" ||
|
||||||
|
data.node.template[t].type === "bool" ||
|
||||||
|
data.node.template[t].type === "float" ||
|
||||||
|
data.node.template[t].type === "code" ||
|
||||||
|
data.node.template[t].type === "prompt" ||
|
||||||
|
data.node.template[t].type === "file" ||
|
||||||
|
data.node.template[t].type === "int")
|
||||||
|
)
|
||||||
|
.map((n, i) => (
|
||||||
|
<TableRow key={i} className="h-8">
|
||||||
|
<TableCell className="p-0 text-center text-gray-900 text-xs dark:text-gray-300">
|
||||||
|
{data.node.template[n].name
|
||||||
|
? data.node.template[n].name
|
||||||
|
: data.node.template[n].display_name}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="p-0 text-center text-gray-900 text-xs w-[300px] dark:text-gray-300">
|
||||||
|
{data.node.template[n].type === "str" &&
|
||||||
|
!data.node.template[n].options ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
{data.node.template[n].list ? (
|
||||||
|
<InputListComponent
|
||||||
|
disabled={false}
|
||||||
|
value={
|
||||||
|
!data.node.template[n].value ||
|
||||||
|
data.node.template[n].value === ""
|
||||||
|
? [""]
|
||||||
|
: data.node.template[n].value
|
||||||
|
}
|
||||||
|
onChange={(t: string[]) => {
|
||||||
|
data.node.template[n].value = t;
|
||||||
|
save();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : data.node.template[n].multiline ? (
|
||||||
|
<TextAreaComponent
|
||||||
|
disabled={false}
|
||||||
|
editNode={true}
|
||||||
|
value={data.node.template[n].value ?? ""}
|
||||||
|
onChange={(t: string) => {
|
||||||
|
data.node.template[n].value = t;
|
||||||
|
save();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<InputComponent
|
||||||
|
editNode={true}
|
||||||
|
disabled={false}
|
||||||
|
password={
|
||||||
|
data.node.template[n].password ?? false
|
||||||
|
}
|
||||||
|
value={data.node.template[n].value ?? ""}
|
||||||
|
onChange={(t) => {
|
||||||
|
data.node.template[n].value = t;
|
||||||
|
save();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : data.node.template[n].type === "bool" ? (
|
||||||
|
<div className="ml-auto">
|
||||||
|
{" "}
|
||||||
|
<ToggleShadComponent
|
||||||
|
enabled={data.node.template[n].value}
|
||||||
|
setEnabled={(e) => {
|
||||||
|
data.node.template[n].value = e;
|
||||||
|
setEnabled(e);
|
||||||
|
save();
|
||||||
|
}}
|
||||||
|
disabled={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : data.node.template[n].type === "float" ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
<FloatComponent
|
||||||
|
disabled={false}
|
||||||
|
editNode={true}
|
||||||
|
value={data.node.template[n].value ?? ""}
|
||||||
|
onChange={(t) => {
|
||||||
|
data.node.template[n].value = t;
|
||||||
|
save();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : data.node.template[n].type === "str" &&
|
||||||
|
data.node.template[n].options ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
<Dropdown
|
||||||
|
editNode={true}
|
||||||
|
options={data.node.template[n].options}
|
||||||
|
onSelect={(newValue) =>
|
||||||
|
(data.node.template[n].value = newValue)
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
data.node.template[n].value ??
|
||||||
|
"Choose an option"
|
||||||
|
}
|
||||||
|
></Dropdown>
|
||||||
|
</div>
|
||||||
|
) : data.node.template[n].type === "int" ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
<IntComponent
|
||||||
|
disabled={false}
|
||||||
|
editNode={true}
|
||||||
|
value={data.node.template[n].value ?? ""}
|
||||||
|
onChange={(t) => {
|
||||||
|
data.node.template[n].value = t;
|
||||||
|
save();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : data.node.template[n].type === "file" ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
<InputFileComponent
|
||||||
|
editNode={true}
|
||||||
|
disabled={false}
|
||||||
|
value={data.node.template[n].value ?? ""}
|
||||||
|
onChange={(t: string) => {
|
||||||
|
data.node.template[n].value = t;
|
||||||
|
}}
|
||||||
|
fileTypes={data.node.template[n].fileTypes}
|
||||||
|
suffixes={data.node.template[n].suffixes}
|
||||||
|
onFileChange={(t: string) => {
|
||||||
|
data.node.template[n].content = t;
|
||||||
|
save();
|
||||||
|
}}
|
||||||
|
></InputFileComponent>
|
||||||
|
</div>
|
||||||
|
) : data.node.template[n].type === "prompt" ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
<PromptAreaComponent
|
||||||
|
editNode={true}
|
||||||
|
disabled={false}
|
||||||
|
value={data.node.template[n].value ?? ""}
|
||||||
|
onChange={(t: string) => {
|
||||||
|
data.node.template[n].value = t;
|
||||||
|
save();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : data.node.template[n].type === "code" ? (
|
||||||
|
<div className="mx-auto">
|
||||||
|
<CodeAreaComponent
|
||||||
|
disabled={false}
|
||||||
|
editNode={true}
|
||||||
|
value={data.node.template[n].value ?? ""}
|
||||||
|
onChange={(t: string) => {
|
||||||
|
data.node.template[n].value = t;
|
||||||
|
save();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : data.node.template[n].type === "Any" ? (
|
||||||
|
"-"
|
||||||
|
) : (
|
||||||
|
<div className="hidden"></div>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="p-0 text-right">
|
||||||
|
<div className="items-center text-center">
|
||||||
|
<ToggleShadComponent
|
||||||
|
enabled={!data.node.template[n].advanced}
|
||||||
|
setEnabled={(e) =>
|
||||||
|
changeAdvanced(data.node.template[n])
|
||||||
|
}
|
||||||
|
disabled={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DialogFooter>
|
||||||
|
<Button
|
||||||
|
className="mt-3"
|
||||||
|
onClick={() => {
|
||||||
|
setModalOpen(false);
|
||||||
|
}}
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
Save changes
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
|
||||||
import { XMarkIcon, CommandLineIcon } from "@heroicons/react/24/outline";
|
import { XMarkIcon, CommandLineIcon } from "@heroicons/react/24/outline";
|
||||||
import { Fragment, useContext, useRef, useState } from "react";
|
import { Fragment, useContext, useRef, useState } from "react";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
import { PopUpContext } from "../../contexts/popUpContext";
|
||||||
|
|
@ -12,6 +11,18 @@ import { darkContext } from "../../contexts/darkContext";
|
||||||
import { checkCode } from "../../controllers/API";
|
import { checkCode } from "../../controllers/API";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "../../components/ui/dialog";
|
||||||
|
import { Button } from "../../components/ui/button";
|
||||||
|
import { CODE_PROMPT_DIALOG_SUBTITLE } from "../../constants";
|
||||||
|
|
||||||
export default function CodeAreaModal({
|
export default function CodeAreaModal({
|
||||||
value,
|
value,
|
||||||
setValue,
|
setValue,
|
||||||
|
|
@ -34,69 +45,21 @@ export default function CodeAreaModal({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={open} appear={true} as={Fragment}>
|
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||||
<Dialog
|
<DialogTrigger></DialogTrigger>
|
||||||
as="div"
|
<DialogContent className="lg:max-w-[700px] h-[500px]">
|
||||||
className="relative z-10"
|
<DialogHeader>
|
||||||
onClose={setModalOpen}
|
<DialogTitle className="flex items-center">
|
||||||
initialFocus={ref}
|
<span className="pr-2">Edit Code</span>
|
||||||
>
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0"
|
|
||||||
enterTo="opacity-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100"
|
|
||||||
leaveTo="opacity-0"
|
|
||||||
>
|
|
||||||
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
|
|
||||||
</Transition.Child>
|
|
||||||
|
|
||||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
|
||||||
<div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
>
|
|
||||||
<Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]">
|
|
||||||
<div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="rounded-md text-gray-400 hover:text-gray-500"
|
|
||||||
onClick={() => {
|
|
||||||
setModalOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="sr-only">Close</span>
|
|
||||||
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="h-full w-full flex flex-col justify-center items-center">
|
|
||||||
<div className="flex w-full pb-4 z-10 justify-center shadow-sm">
|
|
||||||
<div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10">
|
|
||||||
<CommandLineIcon
|
<CommandLineIcon
|
||||||
className="h-6 w-6 text-blue-600"
|
className="h-6 w-6 text-gray-800 pl-1 dark:text-white"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</DialogTitle>
|
||||||
<div className="mt-4 text-center sm:ml-4 sm:text-left">
|
<DialogDescription>{CODE_PROMPT_DIALOG_SUBTITLE}</DialogDescription>
|
||||||
<Dialog.Title
|
</DialogHeader>
|
||||||
as="h3"
|
|
||||||
className="text-lg font-medium dark:text-white leading-10 text-gray-900"
|
<div className="flex h-full w-full mt-2">
|
||||||
>
|
|
||||||
Edit Code
|
|
||||||
</Dialog.Title>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="h-full w-full bg-gray-200 overflow-auto dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center">
|
|
||||||
<div className="flex h-full w-full">
|
|
||||||
<div className="overflow-hidden px-4 py-5 sm:p-6 w-full h-full rounded-lg bg-white dark:bg-gray-800 shadow">
|
|
||||||
<AceEditor
|
<AceEditor
|
||||||
value={code}
|
value={code}
|
||||||
mode="python"
|
mode="python"
|
||||||
|
|
@ -110,25 +73,20 @@ export default function CodeAreaModal({
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setCode(value);
|
setCode(value);
|
||||||
}}
|
}}
|
||||||
className="h-full w-full rounded-lg"
|
className="w-full rounded-lg h-[300px] custom-scroll"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<DialogFooter>
|
||||||
<div className="bg-gray-200 dark:bg-gray-900 w-full pb-3 flex flex-row-reverse px-4">
|
<Button
|
||||||
<button
|
className="mt-3"
|
||||||
type="button"
|
|
||||||
className="inline-flex w-full justify-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 sm:ml-3 sm:w-auto sm:text-sm"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
checkCode(code)
|
checkCode(code)
|
||||||
.then((apiReturn) => {
|
.then((apiReturn) => {
|
||||||
if (apiReturn.data) {
|
if (apiReturn.data) {
|
||||||
let importsErrors = apiReturn.data.imports.errors;
|
let importsErrors = apiReturn.data.imports.errors;
|
||||||
let funcErrors = apiReturn.data.function.errors;
|
let funcErrors = apiReturn.data.function.errors;
|
||||||
if (
|
if (funcErrors.length === 0 && importsErrors.length === 0) {
|
||||||
funcErrors.length === 0 &&
|
|
||||||
importsErrors.length === 0
|
|
||||||
) {
|
|
||||||
setSuccessData({
|
setSuccessData({
|
||||||
title: "Code is ready to run",
|
title: "Code is ready to run",
|
||||||
});
|
});
|
||||||
|
|
@ -161,16 +119,12 @@ export default function CodeAreaModal({
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
type="submit"
|
||||||
>
|
>
|
||||||
Check & Save
|
Check & Save
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</DialogFooter>
|
||||||
</div>
|
</DialogContent>
|
||||||
</Dialog.Panel>
|
|
||||||
</Transition.Child>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
|
||||||
import {
|
import {
|
||||||
XMarkIcon,
|
XMarkIcon,
|
||||||
ArrowDownTrayIcon,
|
ArrowDownTrayIcon,
|
||||||
|
|
@ -10,6 +9,21 @@ import { alertContext } from "../../contexts/alertContext";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
import { PopUpContext } from "../../contexts/popUpContext";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { removeApiKeys } from "../../utils";
|
import { removeApiKeys } from "../../utils";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "../../components/ui/dialog";
|
||||||
|
import { Button } from "../../components/ui/button";
|
||||||
|
import { Label } from "@radix-ui/react-label";
|
||||||
|
import { Checkbox } from "../../components/ui/checkbox";
|
||||||
|
import { Textarea } from "../../components/ui/textarea";
|
||||||
|
import { Input } from "../../components/ui/input";
|
||||||
|
import { EXPORT_DIALOG_SUBTITLE } from "../../constants";
|
||||||
|
|
||||||
export default function ExportModal() {
|
export default function ExportModal() {
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
|
|
@ -28,75 +42,25 @@ export default function ExportModal() {
|
||||||
const [checked, setChecked] = useState(true);
|
const [checked, setChecked] = useState(true);
|
||||||
const [name, setName] = useState(flows[tabIndex].name);
|
const [name, setName] = useState(flows[tabIndex].name);
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={open} appear={true} as={Fragment}>
|
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||||
<Dialog
|
<DialogTrigger asChild></DialogTrigger>
|
||||||
as="div"
|
<DialogContent className="lg:max-w-[600px] h-[420px]">
|
||||||
className="relative z-10"
|
<DialogHeader>
|
||||||
onClose={setModalOpen}
|
<DialogTitle className="flex items-center">
|
||||||
initialFocus={ref}
|
<span className="pr-2">Export</span>
|
||||||
>
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0"
|
|
||||||
enterTo="opacity-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100"
|
|
||||||
leaveTo="opacity-0"
|
|
||||||
>
|
|
||||||
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
|
|
||||||
</Transition.Child>
|
|
||||||
|
|
||||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
|
||||||
<div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
>
|
|
||||||
<Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]">
|
|
||||||
<div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="rounded-md text-gray-400 hover:text-gray-500"
|
|
||||||
onClick={() => {
|
|
||||||
setModalOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="sr-only">Close</span>
|
|
||||||
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="h-full w-full flex flex-col justify-center items-center">
|
|
||||||
<div className="flex w-full pb-4 z-10 justify-center shadow-sm">
|
|
||||||
<div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10">
|
|
||||||
<ArrowDownTrayIcon
|
<ArrowDownTrayIcon
|
||||||
className="h-6 w-6 text-blue-600"
|
className="h-6 w-6 text-gray-800 pl-1 dark:text-white"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</DialogTitle>
|
||||||
<div className="mt-4 text-center sm:ml-4 sm:text-left">
|
<DialogDescription>{EXPORT_DIALOG_SUBTITLE}</DialogDescription>
|
||||||
<Dialog.Title
|
</DialogHeader>
|
||||||
as="h3"
|
|
||||||
className="text-lg font-medium dark:text-white leading-10 text-gray-900"
|
<Label>
|
||||||
>
|
<span className="font-medium">Name</span>
|
||||||
Export
|
|
||||||
</Dialog.Title>
|
<Input
|
||||||
</div>
|
className="mt-2"
|
||||||
</div>
|
|
||||||
<div className="pt-16 flex flex-col items-start justify-start h-full w-full bg-gray-200 dark:bg-gray-900 p-4 gap-16">
|
|
||||||
<div className="w-full">
|
|
||||||
<label
|
|
||||||
htmlFor="name"
|
|
||||||
className="block mb-2 font-medium text-gray-700 dark:text-white"
|
|
||||||
>
|
|
||||||
Name
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
if (event.target.value != "") {
|
if (event.target.value != "") {
|
||||||
let newFlow = flows[tabIndex];
|
let newFlow = flows[tabIndex];
|
||||||
|
|
@ -112,21 +76,11 @@ export default function ExportModal() {
|
||||||
value={name ?? null}
|
value={name ?? null}
|
||||||
placeholder="File name"
|
placeholder="File name"
|
||||||
id="name"
|
id="name"
|
||||||
className="focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500 text-gray-900 dark:text-gray-100"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</Label>
|
||||||
<div className="w-full">
|
<Label>
|
||||||
<label
|
<span className="font-medium">Description (optional)</span>
|
||||||
htmlFor="description"
|
<Textarea
|
||||||
className="block mb-2 font-medium text-gray-700 dark:text-white"
|
|
||||||
>
|
|
||||||
Description{" "}
|
|
||||||
<span className="text-gray-400 text-sm">
|
|
||||||
{" "}
|
|
||||||
(optional)
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
<textarea
|
|
||||||
name="description"
|
name="description"
|
||||||
id="description"
|
id="description"
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
|
|
@ -136,45 +90,37 @@ export default function ExportModal() {
|
||||||
}}
|
}}
|
||||||
value={flows[tabIndex].description ?? null}
|
value={flows[tabIndex].description ?? null}
|
||||||
placeholder="Flow description"
|
placeholder="Flow description"
|
||||||
|
className="max-h-[100px] mt-2"
|
||||||
rows={3}
|
rows={3}
|
||||||
className=" focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 text-gray-900 dark:text-gray-100 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500"
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label htmlFor="checkbox" className="flex items-center">
|
|
||||||
<input
|
|
||||||
onChange={(event) => {
|
|
||||||
setChecked(event.target.checked);
|
|
||||||
}}
|
|
||||||
checked={checked}
|
|
||||||
id="checkbox"
|
|
||||||
type="checkbox"
|
|
||||||
className="h-4 w-4 text-blue-600 border-gray-300 rounded dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500"
|
|
||||||
/>
|
/>
|
||||||
<span className="ml-2 font-medium text-gray-700 dark:text-white">
|
</Label>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Checkbox
|
||||||
|
id="terms"
|
||||||
|
onCheckedChange={(event: boolean) => {
|
||||||
|
setChecked(event);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="terms"
|
||||||
|
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||||
|
>
|
||||||
Save with my API keys
|
Save with my API keys
|
||||||
</span>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex justify-end">
|
|
||||||
<button
|
<DialogFooter>
|
||||||
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (checked) downloadFlow(flows[tabIndex]);
|
if (checked) downloadFlow(flows[tabIndex]);
|
||||||
else downloadFlow(removeApiKeys(flows[tabIndex]));
|
else downloadFlow(removeApiKeys(flows[tabIndex]));
|
||||||
}}
|
}}
|
||||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
|
type="submit"
|
||||||
>
|
>
|
||||||
Download Flow
|
Download Flow
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</DialogFooter>
|
||||||
</div>
|
</DialogContent>
|
||||||
</div>
|
|
||||||
</Dialog.Panel>
|
|
||||||
</Transition.Child>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
|
||||||
import { XMarkIcon, DocumentTextIcon } from "@heroicons/react/24/outline";
|
import { XMarkIcon, DocumentTextIcon } from "@heroicons/react/24/outline";
|
||||||
import { Fragment, useContext, useRef, useState } from "react";
|
import { Fragment, useContext, useRef, useState } from "react";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
import { PopUpContext } from "../../contexts/popUpContext";
|
||||||
|
|
@ -6,6 +5,19 @@ import { darkContext } from "../../contexts/darkContext";
|
||||||
import { checkPrompt } from "../../controllers/API";
|
import { checkPrompt } from "../../controllers/API";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
import { TypeModal } from "../../utils";
|
import { TypeModal } from "../../utils";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "../../components/ui/dialog";
|
||||||
|
import { Button } from "../../components/ui/button";
|
||||||
|
import { Textarea } from "../../components/ui/textarea";
|
||||||
|
import { PROMPT_DIALOG_SUBTITLE, TEXT_DIALOG_SUBTITLE } from "../../constants";
|
||||||
|
|
||||||
export default function PromptAreaModal({
|
export default function PromptAreaModal({
|
||||||
value,
|
value,
|
||||||
setValue,
|
setValue,
|
||||||
|
|
@ -31,92 +43,54 @@ export default function PromptAreaModal({
|
||||||
function setModalOpen(x: boolean) {
|
function setModalOpen(x: boolean) {
|
||||||
setOpen(x);
|
setOpen(x);
|
||||||
if (x === false) {
|
if (x === false) {
|
||||||
setTimeout(() => {
|
|
||||||
closePopUp();
|
closePopUp();
|
||||||
}, 300);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={open} appear={true} as={Fragment}>
|
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||||
<Dialog
|
<DialogTrigger></DialogTrigger>
|
||||||
as="div"
|
<DialogContent className="lg:max-w-[700px]">
|
||||||
className="relative z-10"
|
<DialogHeader>
|
||||||
onClose={setModalOpen}
|
<DialogTitle className="flex items-center">
|
||||||
initialFocus={ref}
|
<span className="pr-2">{myModalTitle}</span>
|
||||||
>
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0"
|
|
||||||
enterTo="opacity-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100"
|
|
||||||
leaveTo="opacity-0"
|
|
||||||
>
|
|
||||||
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
|
|
||||||
</Transition.Child>
|
|
||||||
|
|
||||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
|
||||||
<div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
|
||||||
<Transition.Child
|
|
||||||
as={Fragment}
|
|
||||||
enter="ease-out duration-300"
|
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
||||||
>
|
|
||||||
<Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]">
|
|
||||||
<div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="rounded-md text-gray-400 hover:text-gray-500"
|
|
||||||
onClick={() => {
|
|
||||||
setModalOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="sr-only">Close</span>
|
|
||||||
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="h-full w-full flex flex-col justify-center items-center">
|
|
||||||
<div className="flex w-full pb-4 z-10 justify-center shadow-sm">
|
|
||||||
<div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10">
|
|
||||||
<DocumentTextIcon
|
<DocumentTextIcon
|
||||||
className="h-6 w-6 text-blue-600"
|
className="h-6 w-6 text-gray-800 pl-1 dark:text-white"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</DialogTitle>
|
||||||
<div className="mt-4 text-center sm:ml-4 sm:text-left">
|
<DialogDescription>
|
||||||
<Dialog.Title
|
{(() => {
|
||||||
as="h3"
|
switch (myModalTitle) {
|
||||||
className="text-lg font-medium dark:text-white leading-10 text-gray-900"
|
case "Edit Text":
|
||||||
>
|
return TEXT_DIALOG_SUBTITLE;
|
||||||
{myModalTitle}
|
|
||||||
</Dialog.Title>
|
case "Edit Prompt":
|
||||||
</div>
|
return PROMPT_DIALOG_SUBTITLE;
|
||||||
</div>
|
|
||||||
<div className="h-full w-full bg-gray-200 overflow-auto dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center">
|
default:
|
||||||
<div className="flex h-full w-full">
|
return null;
|
||||||
<div className="overflow-hidden px-4 py-5 sm:p-6 w-full h-full rounded-lg bg-white dark:bg-gray-800 shadow">
|
}
|
||||||
<textarea
|
})()}
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="flex h-full w-full mt-2">
|
||||||
|
<Textarea
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className="form-input h-full w-full rounded-lg border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-white"
|
className="form-input h-[300px] w-full rounded-lg border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-white"
|
||||||
value={myValue}
|
value={myValue}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setMyValue(e.target.value);
|
setMyValue(e.target.value);
|
||||||
setValue(e.target.value);
|
setValue(e.target.value);
|
||||||
}}
|
}}
|
||||||
|
placeholder="Type message here."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<DialogFooter>
|
||||||
<div className="bg-gray-200 dark:bg-gray-900 w-full pb-3 flex flex-row-reverse px-4">
|
<Button
|
||||||
<button
|
className="mt-3"
|
||||||
type="button"
|
|
||||||
className="inline-flex w-full justify-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 sm:ml-3 sm:w-auto sm:text-sm"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
switch (myModalType) {
|
switch (myModalType) {
|
||||||
case 1:
|
case 1:
|
||||||
|
|
@ -126,8 +100,7 @@ export default function PromptAreaModal({
|
||||||
checkPrompt(myValue)
|
checkPrompt(myValue)
|
||||||
.then((apiReturn) => {
|
.then((apiReturn) => {
|
||||||
if (apiReturn.data) {
|
if (apiReturn.data) {
|
||||||
let inputVariables =
|
let inputVariables = apiReturn.data.input_variables;
|
||||||
apiReturn.data.input_variables;
|
|
||||||
if (inputVariables.length === 0) {
|
if (inputVariables.length === 0) {
|
||||||
setErrorData({
|
setErrorData({
|
||||||
title:
|
title:
|
||||||
|
|
@ -142,8 +115,7 @@ export default function PromptAreaModal({
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setErrorData({
|
setErrorData({
|
||||||
title:
|
title: "Something went wrong, please try again",
|
||||||
"Something went wrong, please try again",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -160,16 +132,12 @@ export default function PromptAreaModal({
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
type="submit"
|
||||||
>
|
>
|
||||||
{myButtonText}
|
{myButtonText}
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</DialogFooter>
|
||||||
</div>
|
</DialogContent>
|
||||||
</Dialog.Panel>
|
|
||||||
</Transition.Child>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
import React, { useContext, useState } from "react";
|
||||||
|
import { Menu, Transition } from "@headlessui/react";
|
||||||
|
import { EllipsisVerticalIcon } from "@heroicons/react/20/solid";
|
||||||
|
import {
|
||||||
|
Cog6ToothIcon,
|
||||||
|
TrashIcon,
|
||||||
|
PencilSquareIcon,
|
||||||
|
DocumentDuplicateIcon,
|
||||||
|
DocumentPlusIcon,
|
||||||
|
Square2StackIcon,
|
||||||
|
} from "@heroicons/react/24/outline";
|
||||||
|
import { classNames } from "../../../../utils";
|
||||||
|
import { Fragment } from "react";
|
||||||
|
import NodeModal from "../../../../modals/NodeModal";
|
||||||
|
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||||
|
import { useReactFlow } from "reactflow";
|
||||||
|
import EditNodeModal from "../../../../modals/EditNodeModal";
|
||||||
|
import TooltipReact from "../../../../components/ReactTooltipComponent";
|
||||||
|
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||||
|
|
||||||
|
const NodeToolbarComponent = (props) => {
|
||||||
|
const [nodeLength, setNodeLength] = useState(
|
||||||
|
Object.keys(props.data.node.template).filter(
|
||||||
|
(t) =>
|
||||||
|
t.charAt(0) !== "_" &&
|
||||||
|
props.data.node.template[t].show &&
|
||||||
|
(props.data.node.template[t].type === "str" ||
|
||||||
|
props.data.node.template[t].type === "bool" ||
|
||||||
|
props.data.node.template[t].type === "float" ||
|
||||||
|
props.data.node.template[t].type === "code" ||
|
||||||
|
props.data.node.template[t].type === "prompt" ||
|
||||||
|
props.data.node.template[t].type === "file" ||
|
||||||
|
props.data.node.template[t].type === "Any" ||
|
||||||
|
props.data.node.template[t].type === "int")
|
||||||
|
).length
|
||||||
|
);
|
||||||
|
|
||||||
|
const { setLastCopiedSelection, paste } = useContext(TabsContext);
|
||||||
|
const reactFlowInstance = useReactFlow();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="h-10 w-26">
|
||||||
|
<span className="isolate inline-flex rounded-md shadow-sm">
|
||||||
|
<ShadTooltip delayDuration={1000} content="Delete" side="top">
|
||||||
|
<button
|
||||||
|
className="hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative inline-flex items-center rounded-l-md bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
|
||||||
|
onClick={() => {
|
||||||
|
props.deleteNode(props.data.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TrashIcon className="w-5 h-5 dark:text-gray-300"></TrashIcon>
|
||||||
|
</button>
|
||||||
|
</ShadTooltip>
|
||||||
|
|
||||||
|
<ShadTooltip delayDuration={1000} content="Duplicate" side="top">
|
||||||
|
<button
|
||||||
|
className={classNames(
|
||||||
|
nodeLength > 0
|
||||||
|
? "hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
|
||||||
|
: "hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 rounded-r-md"
|
||||||
|
)}
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
console.log(reactFlowInstance.getNode(props.data.id));
|
||||||
|
paste(
|
||||||
|
{
|
||||||
|
nodes: [reactFlowInstance.getNode(props.data.id)],
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 50,
|
||||||
|
y: 10,
|
||||||
|
paneX: reactFlowInstance.getNode(props.data.id).position.x,
|
||||||
|
paneY: reactFlowInstance.getNode(props.data.id).position.y,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Square2StackIcon className="w-5 h-5 dark:text-gray-300"></Square2StackIcon>
|
||||||
|
</button>
|
||||||
|
</ShadTooltip>
|
||||||
|
|
||||||
|
{nodeLength > 0 && (
|
||||||
|
<ShadTooltip delayDuration={1000} content="Edit" side="top">
|
||||||
|
<button
|
||||||
|
className="hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 rounded-r-md"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
props.openPopUp(<EditNodeModal data={props.data} />);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PencilSquareIcon className="w-5 h-5 dark:text-gray-300"></PencilSquareIcon>
|
||||||
|
</button>
|
||||||
|
</ShadTooltip>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/*
|
||||||
|
<Menu as="div" className="relative inline-block text-left z-100">
|
||||||
|
<button className="hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 rounded-r-md">
|
||||||
|
<div>
|
||||||
|
<Menu.Button className="flex items-center">
|
||||||
|
<EllipsisVerticalIcon
|
||||||
|
className="w-5 h-5 dark:text-gray-300"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</Menu.Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Transition
|
||||||
|
as={Fragment}
|
||||||
|
enter="transition ease-out duration-100"
|
||||||
|
enterFrom="transform opacity-0 scale-95"
|
||||||
|
enterTo="transform opacity-100 scale-100"
|
||||||
|
leave="transition ease-in duration-75"
|
||||||
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
|
leaveTo="transform opacity-0 scale-95"
|
||||||
|
>
|
||||||
|
<Menu.Items className="absolute z-40 mt-2 w-56 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none top-[28px]">
|
||||||
|
<div className="py-1">
|
||||||
|
<Menu.Item>
|
||||||
|
{({ active }) => (
|
||||||
|
<button
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
props.openPopUp(
|
||||||
|
<EditNodeModal data={props.data} />
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
className={classNames(
|
||||||
|
active
|
||||||
|
? "bg-gray-100 text-gray-900"
|
||||||
|
: "text-gray-700",
|
||||||
|
"w-full group flex items-center px-4 py-2 text-sm"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<PencilSquareIcon
|
||||||
|
className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-500"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
{({ active }) => (
|
||||||
|
<button
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
console.log(
|
||||||
|
reactFlowInstance.getNode(props.data.id)
|
||||||
|
);
|
||||||
|
paste(
|
||||||
|
{
|
||||||
|
nodes: [
|
||||||
|
reactFlowInstance.getNode(props.data.id),
|
||||||
|
],
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 50,
|
||||||
|
y: 10,
|
||||||
|
paneX: reactFlowInstance.getNode(props.data.id)
|
||||||
|
.position.x,
|
||||||
|
paneY: reactFlowInstance.getNode(props.data.id)
|
||||||
|
.position.y,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
className={classNames(
|
||||||
|
active
|
||||||
|
? "bg-gray-100 text-gray-900"
|
||||||
|
: "text-gray-700",
|
||||||
|
"w-full group flex items-center px-4 py-2 text-sm"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<DocumentDuplicateIcon
|
||||||
|
className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-500"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
Duplicate
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</Menu.Item>
|
||||||
|
</div>
|
||||||
|
</Menu.Items>
|
||||||
|
</Transition>
|
||||||
|
</button>
|
||||||
|
</Menu> */}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NodeToolbarComponent;
|
||||||
|
|
@ -38,20 +38,25 @@ const nodeTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function FlowPage({ flow }: { flow: FlowType }) {
|
export default function FlowPage({ flow }: { flow: FlowType }) {
|
||||||
let { updateFlow, disableCopyPaste, addFlow, getNodeId, paste } =
|
let {
|
||||||
useContext(TabsContext);
|
updateFlow,
|
||||||
|
disableCopyPaste,
|
||||||
|
addFlow,
|
||||||
|
getNodeId,
|
||||||
|
paste,
|
||||||
|
lastCopiedSelection,
|
||||||
|
setLastCopiedSelection,
|
||||||
|
} = useContext(TabsContext);
|
||||||
const { types, reactFlowInstance, setReactFlowInstance, templates } =
|
const { types, reactFlowInstance, setReactFlowInstance, templates } =
|
||||||
useContext(typesContext);
|
useContext(typesContext);
|
||||||
const reactFlowWrapper = useRef(null);
|
const reactFlowWrapper = useRef(null);
|
||||||
|
|
||||||
const { undo, redo, canUndo, canRedo, takeSnapshot } = useUndoRedo();
|
const { takeSnapshot } = useUndoRedo();
|
||||||
|
|
||||||
const [position, setPosition] = useState({ x: 0, y: 0 });
|
const [position, setPosition] = useState({ x: 0, y: 0 });
|
||||||
const [lastSelection, setLastSelection] =
|
const [lastSelection, setLastSelection] =
|
||||||
useState<OnSelectionChangeParams>(null);
|
useState<OnSelectionChangeParams>(null);
|
||||||
|
|
||||||
const [lastCopiedSelection, setLastCopiedSelection] = useState(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// this effect is used to attach the global event handlers
|
// this effect is used to attach the global event handlers
|
||||||
|
|
||||||
|
|
@ -63,6 +68,7 @@ export default function FlowPage({ flow }: { flow: FlowType }) {
|
||||||
!disableCopyPaste
|
!disableCopyPaste
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
console.log(_.cloneDeep(lastSelection));
|
||||||
setLastCopiedSelection(_.cloneDeep(lastSelection));
|
setLastCopiedSelection(_.cloneDeep(lastSelection));
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ export type InputComponentType = {
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
password: boolean;
|
password: boolean;
|
||||||
disableCopyPaste?: boolean;
|
disableCopyPaste?: boolean;
|
||||||
|
editNode?: boolean;
|
||||||
};
|
};
|
||||||
export type ToggleComponentType = {
|
export type ToggleComponentType = {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
|
@ -22,6 +23,7 @@ export type DropDownComponentType = {
|
||||||
value: string;
|
value: string;
|
||||||
options: string[];
|
options: string[];
|
||||||
onSelect: (value: string) => void;
|
onSelect: (value: string) => void;
|
||||||
|
editNode?: boolean;
|
||||||
};
|
};
|
||||||
export type ParameterComponentType = {
|
export type ParameterComponentType = {
|
||||||
data: NodeDataType;
|
data: NodeDataType;
|
||||||
|
|
@ -44,6 +46,7 @@ export type TextAreaComponentType = {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
onChange: (value: string[] | string) => void;
|
onChange: (value: string[] | string) => void;
|
||||||
value: string;
|
value: string;
|
||||||
|
editNode?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FileComponentType = {
|
export type FileComponentType = {
|
||||||
|
|
@ -53,6 +56,7 @@ export type FileComponentType = {
|
||||||
suffixes: Array<string>;
|
suffixes: Array<string>;
|
||||||
fileTypes: Array<string>;
|
fileTypes: Array<string>;
|
||||||
onFileChange: (value: string) => void;
|
onFileChange: (value: string) => void;
|
||||||
|
editNode?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DisclosureComponentType = {
|
export type DisclosureComponentType = {
|
||||||
|
|
@ -73,6 +77,7 @@ export type FloatComponentType = {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
disableCopyPaste?: boolean;
|
disableCopyPaste?: boolean;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
|
editNode?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TooltipComponentType = {
|
export type TooltipComponentType = {
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,10 @@ export type TabsContextType = {
|
||||||
getNodeId: () => string;
|
getNodeId: () => string;
|
||||||
paste: (
|
paste: (
|
||||||
selection: { nodes: any; edges: any },
|
selection: { nodes: any; edges: any },
|
||||||
position: { x: number; y: number }
|
position: { x: number; y: number; paneX?: number; paneY?: number }
|
||||||
) => void;
|
) => void;
|
||||||
|
lastCopiedSelection: { nodes: any; edges: any };
|
||||||
|
setLastCopiedSelection: (selection: { nodes: any; edges: any }) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LangFlowState = {
|
export type LangFlowState = {
|
||||||
|
|
|
||||||
|
|
@ -535,6 +535,13 @@ export function updateTemplate(
|
||||||
if (objectToUpdate[key] && objectToUpdate[key].value) {
|
if (objectToUpdate[key] && objectToUpdate[key].value) {
|
||||||
clonedObject[key].value = objectToUpdate[key].value;
|
clonedObject[key].value = objectToUpdate[key].value;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
objectToUpdate[key] &&
|
||||||
|
objectToUpdate[key].advanced !== null &&
|
||||||
|
objectToUpdate[key].advanced !== undefined
|
||||||
|
) {
|
||||||
|
clonedObject[key].advanced = objectToUpdate[key].advanced;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return clonedObject;
|
return clonedObject;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,81 @@
|
||||||
const { fontFamily } = require("tailwindcss/defaultTheme")
|
const { fontFamily } = require("tailwindcss/defaultTheme")
|
||||||
|
|
||||||
import plugin from "tailwindcss/plugin";
|
import plugin from "tailwindcss/plugin";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
darkMode: ["class"],
|
||||||
|
content: ["app/**/*.{ts,tsx}", "components/**/*.{ts,tsx}"],
|
||||||
|
theme: {
|
||||||
|
container: {
|
||||||
|
center: true,
|
||||||
|
padding: "2rem",
|
||||||
|
screens: {
|
||||||
|
"2xl": "1400px",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
border: "hsl(var(--border))",
|
||||||
|
input: "hsl(var(--input))",
|
||||||
|
ring: "hsl(var(--ring))",
|
||||||
|
background: "hsl(var(--background))",
|
||||||
|
foreground: "hsl(var(--foreground))",
|
||||||
|
primary: {
|
||||||
|
DEFAULT: "hsl(var(--primary))",
|
||||||
|
foreground: "hsl(var(--primary-foreground))",
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
DEFAULT: "hsl(var(--secondary))",
|
||||||
|
foreground: "hsl(var(--secondary-foreground))",
|
||||||
|
},
|
||||||
|
destructive: {
|
||||||
|
DEFAULT: "hsl(var(--destructive))",
|
||||||
|
foreground: "hsl(var(--destructive-foreground))",
|
||||||
|
},
|
||||||
|
muted: {
|
||||||
|
DEFAULT: "hsl(var(--muted))",
|
||||||
|
foreground: "hsl(var(--muted-foreground))",
|
||||||
|
},
|
||||||
|
accent: {
|
||||||
|
DEFAULT: "hsl(var(--accent))",
|
||||||
|
foreground: "hsl(var(--accent-foreground))",
|
||||||
|
},
|
||||||
|
popover: {
|
||||||
|
DEFAULT: "hsl(var(--popover))",
|
||||||
|
foreground: "hsl(var(--popover-foreground))",
|
||||||
|
},
|
||||||
|
card: {
|
||||||
|
DEFAULT: "hsl(var(--card))",
|
||||||
|
foreground: "hsl(var(--card-foreground))",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
lg: `var(--radius)`,
|
||||||
|
md: `calc(var(--radius) - 2px)`,
|
||||||
|
sm: "calc(var(--radius) - 4px)",
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: ["var(--font-sans)", ...fontFamily.sans],
|
||||||
|
},
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [require("tailwindcss-animate")],
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ["./index.html", "./src/**/*.{js,ts,tsx,jsx}"],
|
content: ["./index.html", "./src/**/*.{js,ts,tsx,jsx}"],
|
||||||
darkMode: "class",
|
darkMode: "class",
|
||||||
|
|
@ -89,6 +164,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
require("tailwindcss-animate"),
|
||||||
require("@tailwindcss/forms")({
|
require("@tailwindcss/forms")({
|
||||||
strategy: "class", // only generate classes
|
strategy: "class", // only generate classes
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue