Merge remote-tracking branch 'origin/dev' into newGroupNode
This commit is contained in:
commit
db4bb0c822
82 changed files with 879 additions and 456 deletions
84
src/frontend/package-lock.json
generated
84
src/frontend/package-lock.json
generated
|
|
@ -8,11 +8,11 @@
|
|||
"name": "langflow",
|
||||
"version": "0.1.2",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.5",
|
||||
"@emotion/styled": "^11.10.5",
|
||||
"@headlessui/react": "^1.7.10",
|
||||
"@heroicons/react": "^2.0.15",
|
||||
"@mui/material": "^5.11.9",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@headlessui/react": "^1.7.17",
|
||||
"@heroicons/react": "^2.0.18",
|
||||
"@mui/material": "^5.14.7",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
|
|
@ -29,20 +29,20 @@
|
|||
"@radix-ui/react-switch": "^1.0.3",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"@radix-ui/react-tooltip": "^1.0.6",
|
||||
"@tabler/icons-react": "^2.18.0",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tabler/icons-react": "^2.32.0",
|
||||
"@tailwindcss/forms": "^0.5.6",
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@types/axios": "^0.14.0",
|
||||
"accordion": "^3.0.2",
|
||||
"ace-builds": "^1.16.0",
|
||||
"ace-builds": "^1.24.1",
|
||||
"add": "^2.0.6",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"axios": "^1.3.2",
|
||||
"axios": "^1.5.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"class-variance-authority": "^0.6.0",
|
||||
"class-variance-authority": "^0.6.1",
|
||||
"clsx": "^1.2.1",
|
||||
"dompurify": "^3.0.4",
|
||||
"esbuild": "^0.17.18",
|
||||
"dompurify": "^3.0.5",
|
||||
"esbuild": "^0.17.19",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.233.0",
|
||||
"moment": "^2.29.4",
|
||||
|
|
@ -50,51 +50,51 @@
|
|||
"react-ace": "^10.1.0",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.2",
|
||||
"react-icons": "^4.8.0",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-router-dom": "^6.8.1",
|
||||
"react-router-dom": "^6.15.0",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-tabs": "^6.0.0",
|
||||
"react-tooltip": "^5.13.1",
|
||||
"react-tabs": "^6.0.2",
|
||||
"react-tooltip": "^5.21.1",
|
||||
"reactflow": "^11.8.3",
|
||||
"rehype-mathjax": "^4.0.2",
|
||||
"rehype-mathjax": "^4.0.3",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remark-math": "^5.1.1",
|
||||
"shadcn-ui": "^0.2.2",
|
||||
"shadcn-ui": "^0.2.3",
|
||||
"short-unique-id": "^4.4.4",
|
||||
"switch": "^0.0.0",
|
||||
"table": "^6.8.1",
|
||||
"tailwind-merge": "^1.13.0",
|
||||
"tailwindcss-animate": "^1.0.5",
|
||||
"tailwind-merge": "^1.14.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"uuid": "^9.0.0",
|
||||
"vite-plugin-svgr": "^3.2.0",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@swc/cli": "^0.1.62",
|
||||
"@swc/core": "^1.3.62",
|
||||
"@swc/core": "^1.3.80",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/node": "^16.18.12",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"@vitejs/plugin-react-swc": "^3.0.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"daisyui": "^3.1.1",
|
||||
"postcss": "^8.4.23",
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/node": "^16.18.46",
|
||||
"@types/react": "^18.2.21",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"daisyui": "^3.6.3",
|
||||
"postcss": "^8.4.29",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-organize-imports": "^3.2.2",
|
||||
"prettier-plugin-organize-imports": "^3.2.3",
|
||||
"prettier-plugin-tailwindcss": "^0.3.0",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^4.3.9"
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^4.4.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
|
|
@ -5522,9 +5522,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/fraction.js": {
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz",
|
||||
"integrity": "sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.1.tgz",
|
||||
"integrity": "sha512-nx0cki48JBA6ThPeUpeKCNpdhEl/9bRS+dAEYnRUod+Z1jhFfC3K/mBLorZZntqHM+GTH3/dkkpfoT3QITYe7g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
|
|
@ -14737,9 +14737,9 @@
|
|||
}
|
||||
},
|
||||
"fraction.js": {
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz",
|
||||
"integrity": "sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.1.tgz",
|
||||
"integrity": "sha512-nx0cki48JBA6ThPeUpeKCNpdhEl/9bRS+dAEYnRUod+Z1jhFfC3K/mBLorZZntqHM+GTH3/dkkpfoT3QITYe7g==",
|
||||
"dev": true
|
||||
},
|
||||
"fs-extra": {
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
"version": "0.1.2",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.5",
|
||||
"@emotion/styled": "^11.10.5",
|
||||
"@headlessui/react": "^1.7.10",
|
||||
"@heroicons/react": "^2.0.15",
|
||||
"@mui/material": "^5.11.9",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@headlessui/react": "^1.7.17",
|
||||
"@heroicons/react": "^2.0.18",
|
||||
"@mui/material": "^5.14.7",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
|
|
@ -24,20 +24,20 @@
|
|||
"@radix-ui/react-switch": "^1.0.3",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"@radix-ui/react-tooltip": "^1.0.6",
|
||||
"@tabler/icons-react": "^2.18.0",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tabler/icons-react": "^2.32.0",
|
||||
"@tailwindcss/forms": "^0.5.6",
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@types/axios": "^0.14.0",
|
||||
"accordion": "^3.0.2",
|
||||
"ace-builds": "^1.16.0",
|
||||
"ace-builds": "^1.24.1",
|
||||
"add": "^2.0.6",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"axios": "^1.3.2",
|
||||
"axios": "^1.5.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"class-variance-authority": "^0.6.0",
|
||||
"class-variance-authority": "^0.6.1",
|
||||
"clsx": "^1.2.1",
|
||||
"dompurify": "^3.0.4",
|
||||
"esbuild": "^0.17.18",
|
||||
"dompurify": "^3.0.5",
|
||||
"esbuild": "^0.17.19",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.233.0",
|
||||
"moment": "^2.29.4",
|
||||
|
|
@ -45,24 +45,24 @@
|
|||
"react-ace": "^10.1.0",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.2",
|
||||
"react-icons": "^4.8.0",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-router-dom": "^6.8.1",
|
||||
"react-router-dom": "^6.15.0",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-tabs": "^6.0.0",
|
||||
"react-tooltip": "^5.13.1",
|
||||
"react-tabs": "^6.0.2",
|
||||
"react-tooltip": "^5.21.1",
|
||||
"reactflow": "^11.8.3",
|
||||
"rehype-mathjax": "^4.0.2",
|
||||
"rehype-mathjax": "^4.0.3",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remark-math": "^5.1.1",
|
||||
"shadcn-ui": "^0.2.2",
|
||||
"shadcn-ui": "^0.2.3",
|
||||
"short-unique-id": "^4.4.4",
|
||||
"switch": "^0.0.0",
|
||||
"table": "^6.8.1",
|
||||
"tailwind-merge": "^1.13.0",
|
||||
"tailwindcss-animate": "^1.0.5",
|
||||
"tailwind-merge": "^1.14.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"uuid": "^9.0.0",
|
||||
"vite-plugin-svgr": "^3.2.0",
|
||||
"web-vitals": "^2.1.4"
|
||||
|
|
@ -96,26 +96,26 @@
|
|||
"proxy": "http://127.0.0.1:7860",
|
||||
"devDependencies": {
|
||||
"@swc/cli": "^0.1.62",
|
||||
"@swc/core": "^1.3.62",
|
||||
"@swc/core": "^1.3.80",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/node": "^16.18.12",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"@vitejs/plugin-react-swc": "^3.0.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"daisyui": "^3.1.1",
|
||||
"postcss": "^8.4.23",
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/node": "^16.18.46",
|
||||
"@types/react": "^18.2.21",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"daisyui": "^3.6.3",
|
||||
"postcss": "^8.4.29",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-organize-imports": "^3.2.2",
|
||||
"prettier-plugin-organize-imports": "^3.2.3",
|
||||
"prettier-plugin-tailwindcss": "^0.3.0",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^4.3.9"
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^4.4.9"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
import { useState } from "react";
|
||||
import { dropdownButtonPropsType } from "../../types/components";
|
||||
import IconComponent from "../genericIconComponent";
|
||||
import { Button } from "../ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "../ui/dropdown-menu";
|
||||
|
||||
export default function DropdownButton({
|
||||
firstButtonName,
|
||||
onFirstBtnClick,
|
||||
options,
|
||||
}: dropdownButtonPropsType): JSX.Element {
|
||||
const [showOptions, setShowOptions] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<DropdownMenu open={showOptions}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="primary"
|
||||
className="relative pr-10"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
onFirstBtnClick();
|
||||
}}
|
||||
>
|
||||
{firstButtonName}
|
||||
<div
|
||||
className="absolute right-2 items-center text-muted-foreground"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
>
|
||||
{!showOptions ? (
|
||||
<IconComponent name="ChevronDown" />
|
||||
) : (
|
||||
<IconComponent name="ChevronUp" />
|
||||
)}
|
||||
</div>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
onPointerDownOutside={(event) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
>
|
||||
{options.map(({ name, onBtnClick }, index) => (
|
||||
<DropdownMenuItem onClick={onBtnClick} key={index}>
|
||||
{name}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -28,7 +28,6 @@ import {
|
|||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "../../components/ui/tabs";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { darkContext } from "../../contexts/darkContext";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import { codeTabsPropsType } from "../../types/components";
|
||||
|
|
@ -49,7 +48,6 @@ export default function CodeTabsComponent({
|
|||
const [openAccordion, setOpenAccordion] = useState<string[]>([]);
|
||||
const { dark } = useContext(darkContext);
|
||||
const { reactFlowInstance } = useContext(typesContext);
|
||||
const { isTweakPage, setIsTweakPage } = useContext(alertContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (flow && flow["data"]!["nodes"]) {
|
||||
|
|
@ -58,16 +56,14 @@ export default function CodeTabsComponent({
|
|||
}, [flow]);
|
||||
|
||||
useEffect(() => {
|
||||
unselectAllNodes({
|
||||
data,
|
||||
updateNodes: (nodes) => {
|
||||
reactFlowInstance?.setNodes(nodes);
|
||||
},
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (isTweakPage) setIsTweakPage(false);
|
||||
};
|
||||
if (tweaks) {
|
||||
unselectAllNodes({
|
||||
data,
|
||||
updateNodes: (nodes) => {
|
||||
reactFlowInstance?.setNodes(nodes);
|
||||
},
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const copyToClipboard = () => {
|
||||
|
|
@ -184,7 +180,7 @@ export default function CodeTabsComponent({
|
|||
key={idx} // Remember to add a unique key prop
|
||||
>
|
||||
{idx < 4 ? (
|
||||
<>
|
||||
<div className="w-full h-full flex flex-col">
|
||||
{tab.description && (
|
||||
<div
|
||||
className="mb-2 w-full text-left text-sm"
|
||||
|
|
@ -198,7 +194,7 @@ export default function CodeTabsComponent({
|
|||
>
|
||||
{tab.code}
|
||||
</SyntaxHighlighter>
|
||||
</>
|
||||
</div>
|
||||
) : idx === 4 ? (
|
||||
<>
|
||||
<div className="api-modal-according-display">
|
||||
|
|
|
|||
|
|
@ -7,8 +7,17 @@ import { alertContext } from "../../contexts/alertContext";
|
|||
import { AuthContext } from "../../contexts/authContext";
|
||||
import { darkContext } from "../../contexts/darkContext";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { gradients } from "../../utils/styleUtils";
|
||||
import IconComponent from "../genericIconComponent";
|
||||
import { Button } from "../ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "../ui/dropdown-menu";
|
||||
import { Separator } from "../ui/separator";
|
||||
import MenuBar from "./components/menuBar";
|
||||
|
||||
|
|
@ -17,8 +26,8 @@ export default function Header(): JSX.Element {
|
|||
const { dark, setDark } = useContext(darkContext);
|
||||
const { notificationCenter } = useContext(alertContext);
|
||||
const location = useLocation();
|
||||
const { logout, autoLogin, isAdmin } = useContext(AuthContext);
|
||||
const { stars } = useContext(darkContext);
|
||||
const { logout, autoLogin, isAdmin, userData } = useContext(AuthContext);
|
||||
const { stars, gradientIndex } = useContext(darkContext);
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
|
|
@ -31,40 +40,6 @@ export default function Header(): JSX.Element {
|
|||
{flows.findIndex((f) => tabId === f.id) !== -1 && tabId !== "" && (
|
||||
<MenuBar flows={flows} tabId={tabId} />
|
||||
)}
|
||||
{!autoLogin && location.pathname !== `/flow/${tabId}` && (
|
||||
<a
|
||||
onClick={() => {
|
||||
logout();
|
||||
navigate("/login");
|
||||
}}
|
||||
className="mx-5 cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
|
||||
>
|
||||
Sign out
|
||||
</a>
|
||||
)}
|
||||
|
||||
{location.pathname === "/admin" && (
|
||||
<a
|
||||
onClick={() => {
|
||||
navigate("/");
|
||||
}}
|
||||
className="cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
|
||||
>
|
||||
Home
|
||||
</a>
|
||||
)}
|
||||
|
||||
{isAdmin &&
|
||||
!autoLogin &&
|
||||
location.pathname !== "/admin" &&
|
||||
location.pathname !== `/flow/${tabId}` && (
|
||||
<a
|
||||
className="cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
|
||||
onClick={() => navigate("/admin")}
|
||||
>
|
||||
Admin page
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div className="round-button-div">
|
||||
<Link to="/">
|
||||
|
|
@ -156,6 +131,44 @@ export default function Header(): JSX.Element {
|
|||
/>
|
||||
</button>
|
||||
)}
|
||||
{!autoLogin && (
|
||||
<>
|
||||
<Separator orientation="vertical" />
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
className={
|
||||
"h-7 w-7 rounded-full focus-visible:outline-0 " +
|
||||
gradients[
|
||||
gradientIndex
|
||||
]
|
||||
}
|
||||
/>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{isAdmin && (
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
onClick={() => navigate("/admin")}
|
||||
>
|
||||
Admin Page
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
onClick={() => {
|
||||
logout();
|
||||
navigate("/login");
|
||||
}}
|
||||
>
|
||||
Sign Out
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export default function InputComponent({
|
|||
{isForm ? (
|
||||
<Form.Control asChild>
|
||||
<Input
|
||||
type={password && !pwdVisible ? "password" : "text"}
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
required={required}
|
||||
|
|
@ -53,6 +54,7 @@ export default function InputComponent({
|
|||
</Form.Control>
|
||||
) : (
|
||||
<Input
|
||||
type="text"
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
required={required}
|
||||
|
|
@ -76,6 +78,8 @@ export default function InputComponent({
|
|||
)}
|
||||
{password && (
|
||||
<button
|
||||
type="button"
|
||||
tabIndex={-1}
|
||||
className={classNames(
|
||||
editNode
|
||||
? "input-component-true-button"
|
||||
|
|
|
|||
16
src/frontend/src/components/skeletonCardComponent/index.tsx
Normal file
16
src/frontend/src/components/skeletonCardComponent/index.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { Skeleton } from "../ui/skeleton";
|
||||
|
||||
export const SkeletonCardComponent = (): JSX.Element => {
|
||||
return (
|
||||
<div className="skeleton-card">
|
||||
<div className="skeleton-card-wrapper">
|
||||
<Skeleton className="h-8 w-8 rounded-full" />
|
||||
<Skeleton className="h-4 w-[120px]" />
|
||||
</div>
|
||||
<div className="skeleton-card-text">
|
||||
<Skeleton className="h-3 w-[250px]" />
|
||||
<Skeleton className="h-3 w-[200px]" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -27,7 +27,7 @@ const DialogOverlay = React.forwardRef<
|
|||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-blur-shared backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in",
|
||||
"fixed top-0 right-0 left-0 bottom-0 overflow-auto inset-0 z-50 bg-blur-shared backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -44,7 +44,7 @@ const DialogContent = React.forwardRef<
|
|||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"noundo nocopy fixed z-50 flex w-full flex-col gap-3 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",
|
||||
"noundo nocopy flex text-start overflow-auto z-50 justify-center items-left flex-col w-full max-w-lg gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-bottom-[48%] data-[state=open]:slide-in-from-bottom-[48%] sm:rounded-lg md:w-full",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
15
src/frontend/src/components/ui/skeleton.tsx
Normal file
15
src/frontend/src/components/ui/skeleton.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { cn } from "../../utils/utils";
|
||||
|
||||
function Skeleton({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div
|
||||
className={cn("animate-pulse rounded-md bg-border", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { Skeleton };
|
||||
|
|
@ -26,8 +26,6 @@ const initialValue: alertContextType = {
|
|||
pushNotificationList: () => {},
|
||||
clearNotificationList: () => {},
|
||||
removeFromNotificationList: () => {},
|
||||
isTweakPage: false,
|
||||
setIsTweakPage: () => {},
|
||||
};
|
||||
|
||||
export const alertContext = createContext<alertContextType>(initialValue);
|
||||
|
|
@ -123,8 +121,6 @@ export function AlertProvider({ children }: { children: ReactNode }) {
|
|||
return (
|
||||
<alertContext.Provider
|
||||
value={{
|
||||
isTweakPage,
|
||||
setIsTweakPage,
|
||||
removeFromNotificationList,
|
||||
clearNotificationList,
|
||||
notificationList,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ const initialValue = {
|
|||
setDark: () => {},
|
||||
stars: 0,
|
||||
setStars: (stars) => 0,
|
||||
gradientIndex: 0,
|
||||
setGradientIndex: () => 0,
|
||||
};
|
||||
|
||||
export const darkContext = createContext<darkContextType>(initialValue);
|
||||
|
|
@ -16,6 +18,7 @@ export function DarkProvider({ children }) {
|
|||
JSON.parse(window.localStorage.getItem("isDark")!) ?? false
|
||||
);
|
||||
const [stars, setStars] = useState<number>(0);
|
||||
const [gradientIndex, setGradientIndex] = useState<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchStars() {
|
||||
|
|
@ -23,6 +26,11 @@ export function DarkProvider({ children }) {
|
|||
setStars(starsCount);
|
||||
}
|
||||
fetchStars();
|
||||
const min = 0;
|
||||
const max = 30;
|
||||
setGradientIndex(
|
||||
Math.floor(Math.random() * (max - min + 1)) + min
|
||||
)
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -41,6 +49,8 @@ export function DarkProvider({ children }) {
|
|||
stars,
|
||||
dark,
|
||||
setDark,
|
||||
setGradientIndex,
|
||||
gradientIndex,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ const TabsContextInitialValue: TabsContextType = {
|
|||
save: () => {},
|
||||
tabId: "",
|
||||
setTabId: (index: string) => {},
|
||||
isLoading: true,
|
||||
flows: [],
|
||||
removeFlow: (id: string) => {},
|
||||
addFlow: async (flowData?: any) => "",
|
||||
|
|
@ -57,7 +58,7 @@ const TabsContextInitialValue: TabsContextType = {
|
|||
downloadFlow: (flow: FlowType) => {},
|
||||
downloadFlows: () => {},
|
||||
uploadFlows: () => {},
|
||||
uploadFlow: () => {},
|
||||
uploadFlow: async () => "",
|
||||
isBuilt: false,
|
||||
setIsBuilt: (state: boolean) => {},
|
||||
hardReset: () => {},
|
||||
|
|
@ -82,10 +83,12 @@ export const TabsContext = createContext<TabsContextType>(
|
|||
export function TabsProvider({ children }: { children: ReactNode }) {
|
||||
const { setErrorData, setNoticeData, setSuccessData } =
|
||||
useContext(alertContext);
|
||||
const { getAuthentication } = useContext(AuthContext);
|
||||
const { getAuthentication, isAuthenticated } = useContext(AuthContext);
|
||||
|
||||
const [tabId, setTabId] = useState("");
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const [flows, setFlows] = useState<Array<FlowType>>([]);
|
||||
const [id, setId] = useState(uid());
|
||||
const { templates, reactFlowInstance } = useContext(typesContext);
|
||||
|
|
@ -96,6 +99,12 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
const [tabsState, setTabsState] = useState<TabsState>({});
|
||||
const [getTweak, setTweak] = useState<tweakType>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated) {
|
||||
hardReset();
|
||||
}
|
||||
}, [isAuthenticated]);
|
||||
|
||||
const newNodeId = useRef(uid());
|
||||
function incrementNodeId() {
|
||||
newNodeId.current = uid();
|
||||
|
|
@ -126,11 +135,13 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
}
|
||||
|
||||
function refreshFlows() {
|
||||
setIsLoading(true);
|
||||
getTabsDataFromDB().then((DbData) => {
|
||||
if (DbData && Object.keys(templates).length > 0) {
|
||||
try {
|
||||
processDBData(DbData);
|
||||
updateStateWithDbData(DbData);
|
||||
setIsLoading(false);
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
|
|
@ -244,6 +255,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
setTabId("");
|
||||
|
||||
setFlows([]);
|
||||
setIsLoading(true);
|
||||
setId(uid());
|
||||
}
|
||||
|
||||
|
|
@ -301,39 +313,40 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
* If the file type is application/json, the file is read and parsed into a JSON object.
|
||||
* The resulting JSON object is passed to the addFlow function.
|
||||
*/
|
||||
function uploadFlow(newProject?: boolean, file?: File) {
|
||||
async function uploadFlow(
|
||||
newProject?: boolean,
|
||||
file?: File
|
||||
): Promise<String | undefined> {
|
||||
let id;
|
||||
if (file) {
|
||||
file.text().then((text) => {
|
||||
// parse the text into a JSON object
|
||||
let flow: FlowType = JSON.parse(text);
|
||||
let text = await file.text();
|
||||
// parse the text into a JSON object
|
||||
let flow: FlowType = JSON.parse(text);
|
||||
|
||||
addFlow(flow, newProject);
|
||||
});
|
||||
id = await addFlow(flow, newProject);
|
||||
} else {
|
||||
// create a file input
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = ".json";
|
||||
// add a change event listener to the file input
|
||||
input.onchange = (e: Event) => {
|
||||
// check if the file type is application/json
|
||||
if (
|
||||
(e.target as HTMLInputElement).files![0].type === "application/json"
|
||||
) {
|
||||
// get the file from the file input
|
||||
const currentfile = (e.target as HTMLInputElement).files![0];
|
||||
// read the file as text
|
||||
currentfile.text().then((text) => {
|
||||
// parse the text into a JSON object
|
||||
id = await new Promise((resolve) => {
|
||||
input.onchange = async (e: Event) => {
|
||||
if (
|
||||
(e.target as HTMLInputElement).files![0].type === "application/json"
|
||||
) {
|
||||
const currentfile = (e.target as HTMLInputElement).files![0];
|
||||
let text = await currentfile.text();
|
||||
let flow: FlowType = JSON.parse(text);
|
||||
|
||||
addFlow(flow, newProject);
|
||||
});
|
||||
}
|
||||
};
|
||||
// trigger the file input click event to open the file dialog
|
||||
input.click();
|
||||
const flowId = await addFlow(flow, newProject);
|
||||
resolve(flowId);
|
||||
}
|
||||
};
|
||||
// trigger the file input click event to open the file dialog
|
||||
input.click();
|
||||
});
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
function uploadFlows() {
|
||||
|
|
@ -665,6 +678,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
paste,
|
||||
getTweak,
|
||||
setTweak,
|
||||
isLoading,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ function ApiInterceptor() {
|
|||
}
|
||||
|
||||
const res = await renewAccessToken(refreshToken);
|
||||
login(res.data.access_token, res.data.refresh_token);
|
||||
login(res?.data?.access_token, res?.data?.refresh_token);
|
||||
try {
|
||||
if (error?.config?.headers) {
|
||||
delete error.config.headers["Authorization"];
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ export async function readFlowsFromDatabase() {
|
|||
try {
|
||||
const response = await api.get(`${BASE_URL_API}flows/`);
|
||||
if (response?.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||
}
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
|
|
@ -177,7 +177,7 @@ export async function downloadFlowsFromDatabase() {
|
|||
try {
|
||||
const response = await api.get(`${BASE_URL_API}flows/download/`);
|
||||
if (response?.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||
}
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
|
|
@ -190,8 +190,8 @@ export async function uploadFlowsToDatabase(flows: FormData) {
|
|||
try {
|
||||
const response = await api.post(`${BASE_URL_API}flows/upload/`, flows);
|
||||
|
||||
if (response.status !== 201) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
if (response?.status !== 201) {
|
||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||
}
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
|
|
@ -312,7 +312,7 @@ export async function getHealth() {
|
|||
*/
|
||||
export async function getBuildStatus(
|
||||
flowId: string
|
||||
): Promise<BuildStatusTypeAPI> {
|
||||
): Promise<AxiosResponse<BuildStatusTypeAPI>> {
|
||||
return await api.get(`${BASE_URL_API}build/${flowId}/status`);
|
||||
}
|
||||
|
||||
|
|
@ -468,7 +468,7 @@ export async function updateUser(user_id: string, user: Users) {
|
|||
|
||||
export async function getApiKey() {
|
||||
try {
|
||||
const res = await api.get(`${BASE_URL_API}api_key`);
|
||||
const res = await api.get(`${BASE_URL_API}api_key/`);
|
||||
if (res.status === 200) {
|
||||
return res.data;
|
||||
}
|
||||
|
|
@ -480,7 +480,7 @@ export async function getApiKey() {
|
|||
|
||||
export async function createApiKey(name: string) {
|
||||
try {
|
||||
const res = await api.post(`${BASE_URL_API}api_key`, { name });
|
||||
const res = await api.post(`${BASE_URL_API}api_key/`, { name });
|
||||
if (res.status === 200) {
|
||||
return res.data;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import { Textarea } from "../../components/ui/textarea";
|
|||
import { CHAT_FORM_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||
import { AuthContext } from "../../contexts/authContext";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { getBuildStatus } from "../../controllers/API";
|
||||
import { TabsState } from "../../types/tabs";
|
||||
import { validateNodes } from "../../utils/reactflowUtils";
|
||||
|
||||
|
|
@ -155,9 +156,23 @@ export default function FormModal({
|
|||
|
||||
function handleOnClose(event: CloseEvent): void {
|
||||
if (isOpen.current) {
|
||||
getBuildStatus(flow.id)
|
||||
.then((response) => {
|
||||
if (response.data.built) {
|
||||
connectWS();
|
||||
} else {
|
||||
setErrorData({
|
||||
title: "Please build the flow again before using the chat.",
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
setErrorData({
|
||||
title: error.data?.detail ? error.data.detail : error.message,
|
||||
});
|
||||
});
|
||||
setErrorData({ title: event.reason });
|
||||
setTimeout(() => {
|
||||
connectWS();
|
||||
setLockChat(false);
|
||||
}, 1000);
|
||||
}
|
||||
|
|
@ -175,7 +190,7 @@ export default function FormModal({
|
|||
|
||||
return `${
|
||||
isDevelopment ? "ws" : webSocketProtocol
|
||||
}://${host}${chatEndpoint}?token=${accessToken}`;
|
||||
}://${host}${chatEndpoint}?token=${encodeURIComponent(accessToken!)}`;
|
||||
}
|
||||
|
||||
function handleWsMessage(data: any) {
|
||||
|
|
@ -260,7 +275,6 @@ export default function FormModal({
|
|||
};
|
||||
newWs.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log("Received data:", data);
|
||||
handleWsMessage(data);
|
||||
//get chat history
|
||||
};
|
||||
|
|
@ -268,7 +282,6 @@ export default function FormModal({
|
|||
handleOnClose(event);
|
||||
};
|
||||
newWs.onerror = (ev) => {
|
||||
console.log(ev, "error");
|
||||
if (flow.id === "") {
|
||||
connectWS();
|
||||
} else {
|
||||
|
|
@ -294,7 +307,6 @@ export default function FormModal({
|
|||
useEffect(() => {
|
||||
connectWS();
|
||||
return () => {
|
||||
console.log("unmount");
|
||||
console.log(ws);
|
||||
if (ws.current) {
|
||||
ws.current.close();
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ export default function GenericModal({
|
|||
}
|
||||
|
||||
function validatePrompt(closeModal: boolean): void {
|
||||
//nodeClass is always null on tweaks
|
||||
postValidatePrompt(field_name, inputValue, nodeClass!)
|
||||
.then((apiReturn) => {
|
||||
if (apiReturn.data) {
|
||||
|
|
@ -135,7 +136,11 @@ export default function GenericModal({
|
|||
setSuccessData({
|
||||
title: "Prompt is ready",
|
||||
});
|
||||
setNodeClass!(apiReturn.data?.frontend_node);
|
||||
if (
|
||||
JSON.stringify(apiReturn.data?.frontend_node) !==
|
||||
JSON.stringify({})
|
||||
)
|
||||
setNodeClass!(apiReturn.data?.frontend_node);
|
||||
setModalOpen(closeModal);
|
||||
setValue(inputValue);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
const { data, templates } = useContext(typesContext);
|
||||
const { flows, tabId, uploadFlow, tabsState, saveFlow, isBuilt } =
|
||||
useContext(TabsContext);
|
||||
const { setSuccessData, setErrorData, setIsTweakPage } =
|
||||
useContext(alertContext);
|
||||
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||
const [dataFilter, setFilterData] = useState(data);
|
||||
const [search, setSearch] = useState("");
|
||||
const isPending = tabsState[tabId]?.isPending;
|
||||
|
|
@ -101,10 +100,7 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
<div className="side-bar-button">
|
||||
{flow && flow.data && (
|
||||
<ApiModal flow={flow} disable={!isBuilt}>
|
||||
<div
|
||||
className={classNames("extra-side-bar-buttons")}
|
||||
onClick={() => setIsTweakPage(true)}
|
||||
>
|
||||
<div className={classNames("extra-side-bar-buttons")}>
|
||||
<IconComponent
|
||||
name="Code2"
|
||||
className={
|
||||
|
|
|
|||
|
|
@ -1,14 +1,33 @@
|
|||
import { useContext, useEffect } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import DropdownButton from "../../components/DropdownButtonComponent";
|
||||
import { CardComponent } from "../../components/cardComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import Header from "../../components/headerComponent";
|
||||
import { SkeletonCardComponent } from "../../components/skeletonCardComponent";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
export default function HomePage(): JSX.Element {
|
||||
const { flows, setTabId, downloadFlows, uploadFlows, addFlow, removeFlow } =
|
||||
useContext(TabsContext);
|
||||
const {
|
||||
flows,
|
||||
setTabId,
|
||||
downloadFlows,
|
||||
uploadFlows,
|
||||
addFlow,
|
||||
removeFlow,
|
||||
uploadFlow,
|
||||
isLoading,
|
||||
} = useContext(TabsContext);
|
||||
const dropdownOptions = [
|
||||
{
|
||||
name: "Import from JSON",
|
||||
onBtnClick: () =>
|
||||
uploadFlow(true).then((id) => {
|
||||
navigate("/flow/" + id);
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
// Set a null id
|
||||
useEffect(() => {
|
||||
|
|
@ -16,6 +35,10 @@ export default function HomePage(): JSX.Element {
|
|||
}, []);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
console.log(isLoading);
|
||||
}, [isLoading]);
|
||||
|
||||
// Personal flows display
|
||||
return (
|
||||
<>
|
||||
|
|
@ -45,48 +68,55 @@ export default function HomePage(): JSX.Element {
|
|||
<IconComponent name="Upload" className="main-page-nav-button" />
|
||||
Upload Collection
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
<DropdownButton
|
||||
firstButtonName="New Project"
|
||||
onFirstBtnClick={() => {
|
||||
addFlow(null!, true).then((id) => {
|
||||
navigate("/flow/" + id);
|
||||
});
|
||||
}}
|
||||
>
|
||||
<IconComponent name="Plus" className="main-page-nav-button" />
|
||||
New Project
|
||||
</Button>
|
||||
options={dropdownOptions}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span className="main-page-description-text">
|
||||
Manage your personal projects. Download or upload your collection.
|
||||
</span>
|
||||
<div className="main-page-flows-display">
|
||||
{flows.map((flow, idx) => (
|
||||
<CardComponent
|
||||
key={idx}
|
||||
flow={flow}
|
||||
id={flow.id}
|
||||
button={
|
||||
<Link to={"/flow/" + flow.id}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="whitespace-nowrap "
|
||||
>
|
||||
<IconComponent
|
||||
name="ExternalLink"
|
||||
className="main-page-nav-button"
|
||||
/>
|
||||
Edit Flow
|
||||
</Button>
|
||||
</Link>
|
||||
}
|
||||
onDelete={() => {
|
||||
removeFlow(flow.id);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{isLoading && flows.length == 0 ? (
|
||||
<>
|
||||
<SkeletonCardComponent />
|
||||
<SkeletonCardComponent />
|
||||
<SkeletonCardComponent />
|
||||
<SkeletonCardComponent />
|
||||
</>
|
||||
) : (
|
||||
flows.map((flow, idx) => (
|
||||
<CardComponent
|
||||
key={idx}
|
||||
flow={flow}
|
||||
id={flow.id}
|
||||
button={
|
||||
<Link to={"/flow/" + flow.id}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="whitespace-nowrap "
|
||||
>
|
||||
<IconComponent
|
||||
name="ExternalLink"
|
||||
className="main-page-nav-button"
|
||||
/>
|
||||
Edit Flow
|
||||
</Button>
|
||||
</Link>
|
||||
}
|
||||
onDelete={() => {
|
||||
removeFlow(flow.id);
|
||||
}}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ export default function LoginPage(): JSX.Element {
|
|||
|
||||
function signIn() {
|
||||
const user: LoginType = {
|
||||
username: username,
|
||||
password: password,
|
||||
username: username.trim(),
|
||||
password: password.trim(),
|
||||
};
|
||||
onLogin(user)
|
||||
.then((user) => {
|
||||
|
|
@ -90,6 +90,7 @@ export default function LoginPage(): JSX.Element {
|
|||
|
||||
<Form.Control asChild>
|
||||
<Input
|
||||
type="username"
|
||||
onChange={({ target: { value } }) => {
|
||||
handleInput({ target: { name: "username", value } });
|
||||
}}
|
||||
|
|
@ -130,12 +131,14 @@ export default function LoginPage(): JSX.Element {
|
|||
</div>
|
||||
<div className="w-full">
|
||||
<Form.Submit asChild>
|
||||
<Button className="mr-3 mt-6 w-full">Sign in</Button>
|
||||
<Button className="mr-3 mt-6 w-full" type="submit">
|
||||
Sign in
|
||||
</Button>
|
||||
</Form.Submit>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<Link to="/signup">
|
||||
<Button className="w-full" variant="outline">
|
||||
<Button className="w-full" variant="outline" type="button">
|
||||
Don't have an account? <b>Sign Up</b>
|
||||
</Button>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ export default function SignUp(): JSX.Element {
|
|||
function handleSignup(): void {
|
||||
const { username, password } = inputState;
|
||||
const newUser: UserInputType = {
|
||||
username,
|
||||
password,
|
||||
username: username.trim(),
|
||||
password: password.trim(),
|
||||
};
|
||||
addUser(newUser)
|
||||
.then((user) => {
|
||||
|
|
@ -84,6 +84,7 @@ export default function SignUp(): JSX.Element {
|
|||
|
||||
<Form.Control asChild>
|
||||
<Input
|
||||
type="username"
|
||||
onChange={({ target: { value } }) => {
|
||||
handleInput({ target: { name: "username", value } });
|
||||
}}
|
||||
|
|
@ -157,6 +158,7 @@ export default function SignUp(): JSX.Element {
|
|||
<div className="w-full">
|
||||
<Form.Submit asChild>
|
||||
<Button
|
||||
type="submit"
|
||||
className="mr-3 mt-6 w-full"
|
||||
onClick={() => {
|
||||
handleSignup();
|
||||
|
|
|
|||
|
|
@ -126,6 +126,18 @@
|
|||
@apply form-input block w-full truncate rounded-md border-border bg-background px-3 text-left shadow-sm placeholder:text-muted-foreground focus:border-ring focus:placeholder-transparent focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm;
|
||||
}
|
||||
|
||||
.skeleton-card {
|
||||
@apply bg-background h-48 p-4 border rounded-lg flex flex-col gap-6;
|
||||
}
|
||||
|
||||
.skeleton-card-wrapper {
|
||||
@apply flex items-center space-x-4;
|
||||
}
|
||||
|
||||
.skeleton-card-text {
|
||||
@apply flex flex-col gap-3;
|
||||
}
|
||||
|
||||
/* The same as primary-input but no-truncate */
|
||||
.textarea-primary {
|
||||
@apply form-input block w-full rounded-md border-border bg-background px-3 text-left shadow-sm placeholder:text-muted-foreground focus:border-ring focus:placeholder-transparent focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm;
|
||||
|
|
|
|||
|
|
@ -36,3 +36,18 @@ pre {
|
|||
.gradient-start {
|
||||
animation: gradient-motion-start 4s infinite forwards;
|
||||
}
|
||||
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
textarea:-webkit-autofill,
|
||||
textarea:-webkit-autofill:hover,
|
||||
textarea:-webkit-autofill:focus,
|
||||
select:-webkit-autofill,
|
||||
select:-webkit-autofill:hover,
|
||||
select:-webkit-autofill:focus {
|
||||
-webkit-text-fill-color: black;
|
||||
-webkit-box-shadow: 0 0 0px 1000px #fff6d0 inset;
|
||||
box-shadow: 0 0 0px 1000px #fff6d0 inset;
|
||||
color: black;
|
||||
}
|
||||
|
|
@ -544,3 +544,9 @@ export type fetchErrorComponentType = {
|
|||
message: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type dropdownButtonPropsType = {
|
||||
firstButtonName: string;
|
||||
onFirstBtnClick: () => void;
|
||||
options: Array<{ name: string; onBtnClick: () => void }>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export type TabsContextType = {
|
|||
saveFlow: (flow: FlowType) => Promise<void>;
|
||||
save: () => void;
|
||||
tabId: string;
|
||||
isLoading: boolean;
|
||||
setTabId: (index: string) => void;
|
||||
flows: Array<FlowType>;
|
||||
removeFlow: (id: string) => void;
|
||||
|
|
@ -23,7 +24,7 @@ export type TabsContextType = {
|
|||
uploadFlows: () => void;
|
||||
isBuilt: boolean;
|
||||
setIsBuilt: (state: boolean) => void;
|
||||
uploadFlow: (newFlow?: boolean, file?: File) => void;
|
||||
uploadFlow: (newFlow?: boolean, file?: File) => Promise<String | undefined>;
|
||||
hardReset: () => void;
|
||||
getNodeId: (nodeType: string) => string;
|
||||
tabsState: TabsState;
|
||||
|
|
|
|||
|
|
@ -41,8 +41,6 @@ export type alertContextType = {
|
|||
removeFromNotificationList: (index: string) => void;
|
||||
loading: boolean;
|
||||
setLoading: (newState: boolean) => void;
|
||||
isTweakPage: boolean;
|
||||
setIsTweakPage: (newState: boolean) => void;
|
||||
};
|
||||
|
||||
export type darkContextType = {
|
||||
|
|
@ -50,6 +48,8 @@ export type darkContextType = {
|
|||
setDark: (newState: {}) => void;
|
||||
stars: number;
|
||||
setStars: (stars: number) => void;
|
||||
gradientIndex: number;
|
||||
setGradientIndex: (index: number) => void;
|
||||
};
|
||||
|
||||
export type locationContextType = {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
ChevronDown,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
ChevronUp,
|
||||
ChevronsLeft,
|
||||
ChevronsRight,
|
||||
ChevronsUpDown,
|
||||
|
|
@ -302,4 +303,5 @@ export const nodeIconsLucide: iconsType = {
|
|||
Key,
|
||||
Unplug,
|
||||
Group
|
||||
ChevronUp,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue