merge fix
This commit is contained in:
commit
3a612c874c
89 changed files with 1296 additions and 1059 deletions
8
src/frontend/package-lock.json
generated
8
src/frontend/package-lock.json
generated
|
|
@ -55,7 +55,7 @@
|
|||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-router-dom": "^6.15.0",
|
||||
|
|
@ -9363,9 +9363,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",
|
||||
"integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz",
|
||||
"integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==",
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-router-dom": "^6.15.0",
|
||||
|
|
|
|||
|
|
@ -211,10 +211,12 @@ export default function GenericNode({
|
|||
}
|
||||
}, [validationStatus, validationStatus?.params]);
|
||||
|
||||
// const showNode = data.showNode ?? true;
|
||||
|
||||
const [showNode, setShowNode] = useState(data.showNode ?? true);
|
||||
|
||||
useEffect(() => {
|
||||
setShowNode(data.showNode ?? true);
|
||||
}, [data.showNode]);
|
||||
|
||||
const nameEditable = true;
|
||||
|
||||
const emojiRegex = /\p{Emoji}/u;
|
||||
|
|
@ -438,7 +440,7 @@ export default function GenericNode({
|
|||
event.preventDefault();
|
||||
}}
|
||||
data-testid={"title-" + data.node?.display_name}
|
||||
className="generic-node-tooltip-div text-primary"
|
||||
className="generic-node-tooltip-div cursor-text text-primary"
|
||||
>
|
||||
{data.node?.display_name}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ export default function DropdownButton({
|
|||
firstButtonName,
|
||||
onFirstBtnClick,
|
||||
options,
|
||||
plusButton = false,
|
||||
dropdownOptions = true,
|
||||
}: dropdownButtonPropsType): JSX.Element {
|
||||
const [showOptions, setShowOptions] = useState<boolean>(false);
|
||||
|
||||
|
|
@ -23,28 +25,33 @@ export default function DropdownButton({
|
|||
<Button
|
||||
id="new-project-btn"
|
||||
variant="primary"
|
||||
className="relative pr-10"
|
||||
className={"relative" + dropdownOptions ? "" : " pr-10"}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
onFirstBtnClick();
|
||||
}}
|
||||
>
|
||||
{plusButton && (
|
||||
<IconComponent name="Plus" className="main-page-nav-button" />
|
||||
)}
|
||||
{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>
|
||||
{dropdownOptions && (
|
||||
<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
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ export default function IOView({
|
|||
{/* TODO ADAPT TO ALL TYPES OF INPUTS AND OUTPUTS */}
|
||||
<BaseModal.Header description={CHAT_FORM_DIALOG_SUBTITLE}>
|
||||
<div className="flex items-center">
|
||||
<span className="pr-2">Chat</span>
|
||||
<span className="pr-2">Interaction Panel</span>
|
||||
<IconComponent
|
||||
name="prompts"
|
||||
className="h-6 w-6 pl-1 text-foreground"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useContext, useEffect } from "react";
|
||||
import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa";
|
||||
import { FaDiscord, FaGithub } from "react-icons/fa";
|
||||
import { RiTwitterXFill } from "react-icons/ri";
|
||||
import { Link, useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import AlertDropdown from "../../alerts/alertDropDown";
|
||||
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
||||
|
|
@ -127,7 +128,7 @@ export default function Header(): JSX.Element {
|
|||
rel="noreferrer"
|
||||
className="text-muted-foreground"
|
||||
>
|
||||
<FaTwitter className="side-bar-button-size" />
|
||||
<RiTwitterXFill className="side-bar-button-size" />
|
||||
</a>
|
||||
<a
|
||||
href="https://discord.gg/EqksyE2EX9"
|
||||
|
|
|
|||
|
|
@ -99,12 +99,16 @@ export default function InputComponent({
|
|||
type="text"
|
||||
onBlur={onInputLostFocus}
|
||||
value={
|
||||
selectedOption !== "" || !onChange ? selectedOption : value
|
||||
(selectedOption !== "" || !onChange) && setSelectedOption
|
||||
? selectedOption
|
||||
: value
|
||||
}
|
||||
autoFocus={autoFocus}
|
||||
disabled={disabled}
|
||||
onClick={() => {
|
||||
(selectedOption !== "" || !onChange) && setShowOptions(true);
|
||||
(selectedOption !== "" || !onChange) &&
|
||||
setSelectedOption &&
|
||||
setShowOptions(true);
|
||||
}}
|
||||
required={required}
|
||||
className={classNames(
|
||||
|
|
@ -115,8 +119,12 @@ export default function InputComponent({
|
|||
? " text-clip password "
|
||||
: "",
|
||||
editNode ? " input-edit-node " : "",
|
||||
password && selectedOption === "" && editNode ? "pr-8" : "",
|
||||
password && selectedOption === "" && !editNode ? "pr-10" : "",
|
||||
password && setSelectedOption ? "pr-16" : "",
|
||||
(!password && setSelectedOption) ||
|
||||
(password && !setSelectedOption)
|
||||
? "pr-8"
|
||||
: "",
|
||||
|
||||
className!
|
||||
)}
|
||||
placeholder={password && editNode ? "Key" : placeholder}
|
||||
|
|
@ -179,18 +187,32 @@ export default function InputComponent({
|
|||
setShowOptions(false);
|
||||
}}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className="group flex w-full items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
<ForwardedIconComponent
|
||||
name="Check"
|
||||
<div
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4 text-primary",
|
||||
"relative mr-2 h-4 w-4",
|
||||
selectedOption === option
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
>
|
||||
<div className="absolute opacity-100 transition-all group-hover:opacity-0">
|
||||
<ForwardedIconComponent
|
||||
name="Check"
|
||||
className="mr-2 h-4 w-4 text-primary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute opacity-0 transition-all group-hover:opacity-100">
|
||||
<ForwardedIconComponent
|
||||
name="X"
|
||||
className="mr-2 h-4 w-4 text-status-red"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{option}
|
||||
</div>
|
||||
{optionButton && optionButton(option)}
|
||||
|
|
@ -206,10 +228,12 @@ export default function InputComponent({
|
|||
<div
|
||||
className={cn(
|
||||
"pointer-events-auto absolute inset-y-0 h-full w-full cursor-pointer",
|
||||
selectedOption !== "" || !onChange ? "" : "hidden"
|
||||
(selectedOption !== "" || !onChange) && setSelectedOption
|
||||
? ""
|
||||
: "hidden"
|
||||
)}
|
||||
onClick={
|
||||
selectedOption !== "" || !onChange
|
||||
(selectedOption !== "" || !onChange) && setSelectedOption
|
||||
? (e) => {
|
||||
setShowOptions((old) => !old);
|
||||
e.preventDefault();
|
||||
|
|
@ -221,30 +245,32 @@ export default function InputComponent({
|
|||
</>
|
||||
)}
|
||||
|
||||
<span
|
||||
className={cn(
|
||||
password && selectedOption === "" ? "right-8" : "right-0",
|
||||
"absolute inset-y-0 flex items-center pr-2.5"
|
||||
)}
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
{setSelectedOption && (
|
||||
<span
|
||||
className={cn(
|
||||
selectedOption !== ""
|
||||
? "text-medium-indigo"
|
||||
: "text-muted-foreground",
|
||||
"hover:text-accent-foreground"
|
||||
password && selectedOption === "" ? "right-8" : "right-0",
|
||||
"absolute inset-y-0 flex items-center pr-2.5"
|
||||
)}
|
||||
>
|
||||
<ForwardedIconComponent
|
||||
name={optionsIcon}
|
||||
className={"h-4 w-4"}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
className={cn(
|
||||
selectedOption !== ""
|
||||
? "text-medium-indigo"
|
||||
: "text-muted-foreground",
|
||||
"hover:text-accent-foreground"
|
||||
)}
|
||||
>
|
||||
<ForwardedIconComponent
|
||||
name={optionsIcon}
|
||||
className={"h-4 w-4"}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
|
||||
{password && selectedOption === "" && (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ export const CODE_DIALOG_SUBTITLE =
|
|||
* @constant
|
||||
*/
|
||||
export const CHAT_FORM_DIALOG_SUBTITLE =
|
||||
"Set up the input variables defined in prompt templates. Interact with agents and chains.";
|
||||
"Adjust or overwrite input values, inspect outputs or interact through the chat console.";
|
||||
|
||||
/**
|
||||
* The base text for subtitle of Edit Node Dialog
|
||||
|
|
@ -732,12 +732,12 @@ export const PRIORITY_SIDEBAR_ORDER = [
|
|||
"saved_components",
|
||||
"inputs",
|
||||
"outputs",
|
||||
"prompts",
|
||||
"data",
|
||||
"prompt",
|
||||
"models",
|
||||
"vectorstores",
|
||||
"vectorsearch",
|
||||
"helpers",
|
||||
"experimental",
|
||||
];
|
||||
export const NATIVE_CATEGORIES = [
|
||||
"inputs",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export default function ChatInput({
|
|||
<div className="relative">
|
||||
<Textarea
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" && !lockChat && !event.shiftKey) {
|
||||
if (event.key === "Enter" && !event.nativeEvent.isComposing && !lockChat && !event.shiftKey) {
|
||||
sendMessage();
|
||||
}
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
|||
import IconComponent from "../../../../components/genericIconComponent";
|
||||
import { Input } from "../../../../components/ui/input";
|
||||
import { Separator } from "../../../../components/ui/separator";
|
||||
import { PRIORITY_SIDEBAR_ORDER } from "../../../../constants/constants";
|
||||
import ExportModal from "../../../../modals/exportModal";
|
||||
import ShareModal from "../../../../modals/shareModal";
|
||||
import useAlertStore from "../../../../stores/alertStore";
|
||||
|
|
@ -282,35 +281,7 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{index === PRIORITY_SIDEBAR_ORDER.length - 1 && (
|
||||
<>
|
||||
<a
|
||||
target={"_blank"}
|
||||
href="https://langflow.store"
|
||||
className="components-disclosure-arrangement"
|
||||
>
|
||||
<div className="flex gap-4">
|
||||
{/* BUG ON THIS ICON */}
|
||||
<SparklesIcon
|
||||
strokeWidth={1.5}
|
||||
className="w-[22px] text-primary"
|
||||
/>
|
||||
|
||||
<span className="components-disclosure-title">
|
||||
Discover More
|
||||
</span>
|
||||
</div>
|
||||
<div className="components-disclosure-div">
|
||||
<div>
|
||||
<LinkIcon className="h-4 w-4 text-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div className="p-2 px-4 text-sm font-semibold" key={index}>
|
||||
Legacy Components
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<DisclosureComponent
|
||||
openDisc={
|
||||
getFilterEdge.length !== 0 || search.length !== 0
|
||||
|
|
@ -371,6 +342,32 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
))}
|
||||
</div>
|
||||
</DisclosureComponent>
|
||||
{index === Object.keys(dataFilter).length - 1 && (
|
||||
<>
|
||||
<a
|
||||
target={"_blank"}
|
||||
href="https://langflow.store"
|
||||
className="components-disclosure-arrangement"
|
||||
>
|
||||
<div className="flex gap-4">
|
||||
{/* BUG ON THIS ICON */}
|
||||
<SparklesIcon
|
||||
strokeWidth={1.5}
|
||||
className="w-[22px] text-primary"
|
||||
/>
|
||||
|
||||
<span className="components-disclosure-title">
|
||||
Discover More
|
||||
</span>
|
||||
</div>
|
||||
<div className="components-disclosure-div">
|
||||
<div>
|
||||
<LinkIcon className="h-4 w-4 text-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div key={index}></div>
|
||||
|
|
|
|||
|
|
@ -85,7 +85,9 @@ export default function NodeToolbarComponent({
|
|||
const [showModalAdvanced, setShowModalAdvanced] = useState(false);
|
||||
const [showconfirmShare, setShowconfirmShare] = useState(false);
|
||||
const [showOverrideModal, setShowOverrideModal] = useState(false);
|
||||
const [flowComponent, setFlowComponent] = useState<FlowType>();
|
||||
const [flowComponent, setFlowComponent] = useState<FlowType>(
|
||||
createFlowComponent(cloneDeep(data), version)
|
||||
);
|
||||
|
||||
const openInNewTab = (url) => {
|
||||
window.open(url, "_blank", "noreferrer");
|
||||
|
|
@ -285,7 +287,13 @@ export default function NodeToolbarComponent({
|
|||
event.preventDefault();
|
||||
setShowconfirmShare((state) => !state);
|
||||
}
|
||||
if (selected && (event.ctrlKey || event.metaKey) && event.key === "q") {
|
||||
|
||||
if (
|
||||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "Q"
|
||||
) {
|
||||
event.preventDefault();
|
||||
if (isMinimal) {
|
||||
setShowState((show) => !show);
|
||||
|
|
@ -341,6 +349,10 @@ export default function NodeToolbarComponent({
|
|||
title: `${data.id} docs is not available at the moment.`,
|
||||
});
|
||||
}
|
||||
if (selected && (event.ctrlKey || event.metaKey) && event.key === "j") {
|
||||
event.preventDefault();
|
||||
downloadNode(flowComponent!);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
|
|
@ -499,15 +511,17 @@ export default function NodeToolbarComponent({
|
|||
/>
|
||||
</SelectItem>
|
||||
)}
|
||||
{!hasStore && (
|
||||
{(!hasStore || !hasApiKey || !validApiKey) && (
|
||||
<SelectItem value={"Download"}>
|
||||
<div className="flex">
|
||||
<IconComponent
|
||||
name="Download"
|
||||
className="relative top-0.5 mr-2 h-4 w-4"
|
||||
/>{" "}
|
||||
Download{" "}
|
||||
</div>{" "}
|
||||
<ToolbarSelectItem
|
||||
value="Download"
|
||||
shift={false}
|
||||
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
|
||||
icon="Download"
|
||||
styleObj={{ iconClasses: "relative top-0.5 mr-2 h-4 w-4" }}
|
||||
keyboardKey={"J"}
|
||||
dataTestId={"Dowload-button-nodeToolbar"}
|
||||
/>
|
||||
</SelectItem>
|
||||
)}
|
||||
<SelectItem
|
||||
|
|
@ -525,24 +539,14 @@ export default function NodeToolbarComponent({
|
|||
</SelectItem>
|
||||
{isMinimal && (
|
||||
<SelectItem value={"show"}>
|
||||
<div className="flex">
|
||||
<IconComponent
|
||||
name={showNode ? "Minimize2" : "Maximize2"}
|
||||
className="relative top-0.5 mr-2 h-4 w-4"
|
||||
/>
|
||||
{showNode ? "Minimize" : "Expand"}
|
||||
{navigator.userAgent.toUpperCase().includes("MAC") ? (
|
||||
<IconComponent
|
||||
name="Command"
|
||||
className="absolute right-[1.25rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
|
||||
></IconComponent>
|
||||
) : (
|
||||
<span className="absolute right-[1.30rem] top-[0.40em] stroke-2">
|
||||
Ctrl +{" "}
|
||||
</span>
|
||||
)}
|
||||
<span className="absolute right-2 top-[0.46em]">Q</span>
|
||||
</div>
|
||||
<ToolbarSelectItem
|
||||
icon={showNode ? "Minimize2" : "Maximize2"}
|
||||
value={showNode ? "Minimize" : "Expand"}
|
||||
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
|
||||
shift={true}
|
||||
keyboardKey={"Q"}
|
||||
dataTestId={"minimize-button-nodeToolbar"}
|
||||
/>
|
||||
</SelectItem>
|
||||
)}
|
||||
{isGroup && (
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ export default function HomePage(): JSX.Element {
|
|||
firstButtonName="New Project"
|
||||
onFirstBtnClick={() => setOpenModal(true)}
|
||||
options={dropdownOptions}
|
||||
plusButton={true}
|
||||
dropdownOptions={false}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { DarkStoreType } from "../types/zustand/dark";
|
|||
|
||||
const startedStars = Number(window.localStorage.getItem("githubStars")) ?? 0;
|
||||
|
||||
export const useDarkStore = create<DarkStoreType>((set) => ({
|
||||
export const useDarkStore = create<DarkStoreType>((set, get) => ({
|
||||
dark: JSON.parse(window.localStorage.getItem("isDark")!) ?? false,
|
||||
stars: startedStars,
|
||||
version: "",
|
||||
|
|
@ -15,14 +15,23 @@ export const useDarkStore = create<DarkStoreType>((set) => ({
|
|||
});
|
||||
},
|
||||
refreshStars: () => {
|
||||
if (window.localStorage.getItem("githubStars") !== null) {
|
||||
set(() => ({ stars: startedStars }));
|
||||
return;
|
||||
let lastUpdated = window.localStorage.getItem("githubStarsLastUpdated");
|
||||
let diff = 0;
|
||||
// check if lastUpdated actually exists
|
||||
if (lastUpdated !== null) {
|
||||
diff = Math.abs(new Date().getTime() - new Date(lastUpdated).getTime());
|
||||
}
|
||||
|
||||
getRepoStars("logspace-ai", "langflow").then((res) => {
|
||||
window.localStorage.setItem("githubStars", res.toString());
|
||||
set(() => ({ stars: res }));
|
||||
});
|
||||
// if lastUpdated is null or the difference is greater than 2 hours
|
||||
if (lastUpdated === null || diff > 7200000) {
|
||||
getRepoStars("logspace-ai", "langflow").then((res) => {
|
||||
window.localStorage.setItem("githubStars", res.toString());
|
||||
window.localStorage.setItem(
|
||||
"githubStarsLastUpdated",
|
||||
new Date().toString()
|
||||
);
|
||||
set(() => ({ stars: res, lastUpdated: new Date() }));
|
||||
});
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -689,6 +689,8 @@ export type dropdownButtonPropsType = {
|
|||
firstButtonName: string;
|
||||
onFirstBtnClick: () => void;
|
||||
options: Array<{ name: string; onBtnClick: () => void }>;
|
||||
plusButton?: boolean;
|
||||
dropdownOptions?: boolean;
|
||||
};
|
||||
|
||||
export type IOInputProps = {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ export async function buildVertices({
|
|||
try {
|
||||
onValidateNodes(verticesOrderResponse.verticesToRun);
|
||||
} catch (e) {
|
||||
useFlowStore.getState().setIsBuilding(false);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1170,7 +1170,7 @@ export function downloadNode(NodeFLow: FlowType) {
|
|||
type: "application/json",
|
||||
});
|
||||
element.href = URL.createObjectURL(file);
|
||||
element.download = `${NodeFLow.name}.json`;
|
||||
element.download = `${NodeFLow?.name??"node"}.json`;
|
||||
element.click();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ export const nodeColors: { [char: string]: string } = {
|
|||
embeddings: "#42BAA7",
|
||||
documentloaders: "#7AAE42",
|
||||
vectorstores: "#AA8742",
|
||||
vectorsearch: "#AA8742",
|
||||
textsplitters: "#B47CB5",
|
||||
toolkits: "#DB2C2C",
|
||||
wrappers: "#E6277A",
|
||||
|
|
@ -248,6 +249,7 @@ export const nodeColors: { [char: string]: string } = {
|
|||
retrievers: "#e6b25a",
|
||||
unknown: "#9CA3AF",
|
||||
custom_components: "#ab11ab",
|
||||
Record:"#31a3cc"
|
||||
};
|
||||
|
||||
export const nodeNames: { [char: string]: string } = {
|
||||
|
|
@ -267,6 +269,7 @@ export const nodeNames: { [char: string]: string } = {
|
|||
embeddings: "Embeddings",
|
||||
documentloaders: "Loaders",
|
||||
vectorstores: "Vector Stores",
|
||||
vectorsearch: "Vector Search",
|
||||
toolkits: "Toolkits",
|
||||
wrappers: "Wrappers",
|
||||
textsplitters: "Text Splitters",
|
||||
|
|
@ -369,6 +372,7 @@ export const nodeIconsLucide: iconsType = {
|
|||
saved_components: GradientSave,
|
||||
documentloaders: Paperclip,
|
||||
vectorstores: Layers,
|
||||
vectorsearch: Search,
|
||||
toolkits: Package2,
|
||||
textsplitters: Scissors,
|
||||
wrappers: Gift,
|
||||
|
|
@ -387,7 +391,6 @@ export const nodeIconsLucide: iconsType = {
|
|||
Trash2,
|
||||
Boxes,
|
||||
Network,
|
||||
X,
|
||||
XCircle,
|
||||
Info,
|
||||
CheckCircle2,
|
||||
|
|
|
|||
358
src/frontend/tests/end-to-end/assets/ChatTest.json
Normal file
358
src/frontend/tests/end-to-end/assets/ChatTest.json
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
{
|
||||
"id": "3f5e860d-1676-4fba-9d86-06db9f51e43a",
|
||||
"data": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "ChatInput-7hPDT",
|
||||
"type": "genericNode",
|
||||
"position": {
|
||||
"x": 687,
|
||||
"y": 41.9375
|
||||
},
|
||||
"data": {
|
||||
"type": "ChatInput",
|
||||
"node": {
|
||||
"template": {
|
||||
"code": {
|
||||
"type": "code",
|
||||
"required": true,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Used to get user input from the chat.\"\n icon = \"ChatInput\"\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "code",
|
||||
"advanced": true,
|
||||
"dynamic": true,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"input_value": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "input_value",
|
||||
"display_name": "Message",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"return_record": {
|
||||
"type": "bool",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": false,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "return_record",
|
||||
"display_name": "Return Record",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "Return the message as a record containing the sender, sender_name, and session_id.",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"sender": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": true,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": "User",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": "User",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "sender_name",
|
||||
"display_name": "Sender Name",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "session_id",
|
||||
"display_name": "Session ID",
|
||||
"advanced": true,
|
||||
"dynamic": false,
|
||||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Used to get user input from the chat.",
|
||||
"icon": "ChatInput",
|
||||
"base_classes": ["Text", "object", "str", "Record"],
|
||||
"display_name": "Chat Input",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"sender": null,
|
||||
"sender_name": null,
|
||||
"input_value": null,
|
||||
"session_id": null,
|
||||
"return_record": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
"beta": false
|
||||
},
|
||||
"id": "ChatInput-7hPDT"
|
||||
},
|
||||
"selected": false,
|
||||
"width": 384,
|
||||
"height": 569,
|
||||
"positionAbsolute": {
|
||||
"x": 687,
|
||||
"y": 41.9375
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"id": "ChatOutput-4sm9Z",
|
||||
"type": "genericNode",
|
||||
"position": {
|
||||
"x": 4.939451516507972,
|
||||
"y": 103.3695231904992
|
||||
},
|
||||
"data": {
|
||||
"type": "ChatOutput",
|
||||
"node": {
|
||||
"template": {
|
||||
"code": {
|
||||
"type": "code",
|
||||
"required": true,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Used to send a message to the chat.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "code",
|
||||
"advanced": true,
|
||||
"dynamic": true,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"input_value": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "input_value",
|
||||
"display_name": "Message",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"return_record": {
|
||||
"type": "bool",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": false,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "return_record",
|
||||
"display_name": "Return Record",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "Return the message as a record containing the sender, sender_name, and session_id.",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"sender": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": true,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": "Machine",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": "AI",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "sender_name",
|
||||
"display_name": "Sender Name",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "session_id",
|
||||
"display_name": "Session ID",
|
||||
"advanced": true,
|
||||
"dynamic": false,
|
||||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Used to send a message to the chat.",
|
||||
"icon": "ChatOutput",
|
||||
"base_classes": ["Text", "object", "str", "Record"],
|
||||
"display_name": "Chat Output",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"sender": null,
|
||||
"sender_name": null,
|
||||
"input_value": null,
|
||||
"session_id": null,
|
||||
"return_record": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
"beta": false
|
||||
},
|
||||
"id": "ChatOutput-4sm9Z"
|
||||
},
|
||||
"selected": true,
|
||||
"width": 384,
|
||||
"height": 569,
|
||||
"positionAbsolute": {
|
||||
"x": 4.939451516507972,
|
||||
"y": 103.3695231904992
|
||||
},
|
||||
"dragging": false
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "ChatOutput-4sm9Z",
|
||||
"sourceHandle": "{œbaseClassesœ:[œTextœ,œobjectœ,œstrœ,œRecordœ],œdataTypeœ:œChatOutputœ,œidœ:œChatOutput-4sm9Zœ}",
|
||||
"target": "ChatInput-7hPDT",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatInput-7hPDTœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "ChatInput-7hPDT",
|
||||
"inputTypes": ["Text"],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["Text", "object", "str", "Record"],
|
||||
"dataType": "ChatOutput",
|
||||
"id": "ChatOutput-4sm9Z"
|
||||
}
|
||||
},
|
||||
"style": {
|
||||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-ChatOutput-4sm9Z{œbaseClassesœ:[œTextœ,œobjectœ,œstrœ,œRecordœ],œdataTypeœ:œChatOutputœ,œidœ:œChatOutput-4sm9Zœ}-ChatInput-7hPDT{œfieldNameœ:œinput_valueœ,œidœ:œChatInput-7hPDTœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
}
|
||||
],
|
||||
"viewport": {
|
||||
"x": 316.78239920440234,
|
||||
"y": 182.84104875768622,
|
||||
"zoom": 0.6070974421975234
|
||||
}
|
||||
},
|
||||
"description": "flow to test ChatInput and output",
|
||||
"name": "ChatITest",
|
||||
"last_tested_version": "1.0.0a0",
|
||||
"is_component": false
|
||||
}
|
||||
46
src/frontend/tests/end-to-end/chat_io.spec.ts
Normal file
46
src/frontend/tests/end-to-end/chat_io.spec.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { test } from "@playwright/test";
|
||||
import { readFileSync } from "fs";
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// await page.waitForTimeout(20000);
|
||||
// test.setTimeout(120000);
|
||||
});
|
||||
test("chat_io_teste", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.locator("span").filter({ hasText: "My Collection" }).isVisible();
|
||||
// Read your file into a buffer.
|
||||
const jsonContent = readFileSync(
|
||||
"tests/end-to-end/assets/ChatTest.json",
|
||||
"utf-8"
|
||||
);
|
||||
|
||||
// Create the DataTransfer and File
|
||||
const dataTransfer = await page.evaluateHandle((data) => {
|
||||
const dt = new DataTransfer();
|
||||
// Convert the buffer to a hex array
|
||||
const file = new File([data], "ChatTest.json", {
|
||||
type: "application/json",
|
||||
});
|
||||
dt.items.add(file);
|
||||
return dt;
|
||||
}, jsonContent);
|
||||
|
||||
await page.locator('//*[@id="new-project-btn"]').click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.getByTestId("blank-flow").click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Now dispatch
|
||||
await page.dispatchEvent(
|
||||
'//*[@id="react-flow-id"]/div[1]/div[1]/div',
|
||||
"drop",
|
||||
{
|
||||
dataTransfer,
|
||||
}
|
||||
);
|
||||
await page.getByLabel("fit view").click();
|
||||
await page.getByText("Run", { exact: true }).click();
|
||||
await page.getByPlaceholder("Send a message...").click();
|
||||
await page.getByPlaceholder("Send a message...").fill("teste");
|
||||
await page.getByRole("button").nth(1).click();
|
||||
});
|
||||
|
|
@ -25,86 +25,31 @@ test("CodeAreaModalComponent", async ({ page }) => {
|
|||
await page.getByTestId("code-button-modal").click();
|
||||
|
||||
let value = await page.locator('//*[@id="codeValue"]').inputValue();
|
||||
|
||||
if (
|
||||
value !=
|
||||
'def python_function(text: str) -> str: """This is a default python function that returns the input text""" return text'
|
||||
) {
|
||||
expect(false).toBeTruthy();
|
||||
}
|
||||
|
||||
const code =
|
||||
'def python_function(text: str) -> str:\n """This is a default python function that returns the input text"""\n return text';
|
||||
const wCode =
|
||||
'def python_function(text: str) -> st: """This is a default python function that returns the input text""" return text';
|
||||
const assertCode =
|
||||
'def python_function(text: str) -> str: """This is a default python function that returns the input text""" return text';
|
||||
await page
|
||||
.locator("#CodeEditor div")
|
||||
.filter({ hasText: "def python_function(text: str" })
|
||||
.nth(1)
|
||||
.click();
|
||||
await page.locator("textarea").press("Control+a");
|
||||
await page.locator("textarea").fill(wCode);
|
||||
await page.locator('//*[@id="checkAndSaveBtn"]').click();
|
||||
|
||||
await page.getByTestId("div-generic-node").click();
|
||||
|
||||
await page.getByTestId("more-options-modal").click();
|
||||
await page.getByTestId("edit-button-modal").click();
|
||||
|
||||
await page.locator('//*[@id="showdescription"]').click();
|
||||
await page.waitForTimeout(1000);
|
||||
expect(
|
||||
await page.locator('//*[@id="showdescription"]').isChecked()
|
||||
).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showname"]').click();
|
||||
expect(await page.locator('//*[@id="showname"]').isChecked()).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showreturn_direct"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showreturn_direct"]').isChecked()
|
||||
).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showdescription"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showdescription"]').isChecked()
|
||||
await page.getByText("invalid syntax (<unknown>, line 1)").isVisible()
|
||||
).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="showname"]').click();
|
||||
expect(await page.locator('//*[@id="showname"]').isChecked()).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="showreturn_direct"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showreturn_direct"]').isChecked()
|
||||
).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="showdescription"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showdescription"]').isChecked()
|
||||
).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showname"]').click();
|
||||
expect(await page.locator('//*[@id="showname"]').isChecked()).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showreturn_direct"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showreturn_direct"]').isChecked()
|
||||
).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showdescription"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showdescription"]').isChecked()
|
||||
).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="showname"]').click();
|
||||
expect(await page.locator('//*[@id="showname"]').isChecked()).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="showreturn_direct"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showreturn_direct"]').isChecked()
|
||||
).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="saveChangesBtn"]').click();
|
||||
|
||||
const plusButtonLocator = page.locator('//*[@id="code-input-0"]');
|
||||
const elementCount = await plusButtonLocator.count();
|
||||
if (elementCount === 0) {
|
||||
expect(true).toBeTruthy();
|
||||
|
||||
await page.getByTestId("more-options-modal").click();
|
||||
await page.getByTestId("edit-button-modal").click();
|
||||
|
||||
await page.locator('//*[@id="saveChangesBtn"]').click();
|
||||
|
||||
await page.getByTestId("div-generic-node").click();
|
||||
await page.getByTestId("code-button-modal").click();
|
||||
}
|
||||
await page.locator("textarea").press("Control+a");
|
||||
await page.locator("textarea").fill(wCode);
|
||||
await page.locator("textarea").fill(code);
|
||||
await page.locator('//*[@id="checkAndSaveBtn"]').click();
|
||||
expect(await page.getByText("Code is ready to run").isVisible()).toBeTruthy();
|
||||
await page.getByTestId("code-button-modal").click();
|
||||
expect(await page.locator('//*[@id="codeValue"]').inputValue()).toBe(
|
||||
assertCode
|
||||
);
|
||||
});
|
||||
|
|
|
|||
17
src/frontend/tests/end-to-end/curl_api_generation.spec.ts
Normal file
17
src/frontend/tests/end-to-end/curl_api_generation.spec.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("curl_api_generation", async ({ page, context }) => {
|
||||
await page.goto("/");
|
||||
await page.locator('//*[@id="new-project-btn"]').click();
|
||||
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
|
||||
await page.getByRole("heading", { name: "Data Ingestion" }).click();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.getByText("API", { exact: true }).click();
|
||||
await page.getByRole("tab", { name: "cURL" }).click();
|
||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||
const handle = await page.evaluateHandle(() =>
|
||||
navigator.clipboard.readText()
|
||||
);
|
||||
const clipboardContent = await handle.jsonValue();
|
||||
expect(clipboardContent.length).toBeGreaterThan(0);
|
||||
});
|
||||
17
src/frontend/tests/end-to-end/python_api_generation.spec.ts
Normal file
17
src/frontend/tests/end-to-end/python_api_generation.spec.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("python_api_generation", async ({ page, context }) => {
|
||||
await page.goto("/");
|
||||
await page.locator('//*[@id="new-project-btn"]').click();
|
||||
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
|
||||
await page.getByRole("heading", { name: "Data Ingestion" }).click();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.getByText("API", { exact: true }).click();
|
||||
await page.getByRole("tab", { name: "Python API" }).click();
|
||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||
const handle = await page.evaluateHandle(() =>
|
||||
navigator.clipboard.readText()
|
||||
);
|
||||
const clipboardContent = await handle.jsonValue();
|
||||
expect(clipboardContent.length).toBeGreaterThan(0);
|
||||
});
|
||||
38
src/frontend/tests/end-to-end/tweaks_test.spec.ts
Normal file
38
src/frontend/tests/end-to-end/tweaks_test.spec.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("curl_api_generation", async ({ page, context }) => {
|
||||
await page.goto("/");
|
||||
await page.locator('//*[@id="new-project-btn"]').click();
|
||||
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
|
||||
await page.getByRole("heading", { name: "Data Ingestion" }).click();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.getByText("API", { exact: true }).click();
|
||||
await page.getByRole("tab", { name: "cURL" }).click();
|
||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||
const handle = await page.evaluateHandle(() =>
|
||||
navigator.clipboard.readText()
|
||||
);
|
||||
const clipboardContent = await handle.jsonValue();
|
||||
const oldValue = clipboardContent;
|
||||
expect(clipboardContent.length).toBeGreaterThan(0);
|
||||
await page.getByRole("tab", { name: "Tweaks" }).click();
|
||||
await page
|
||||
.getByRole("heading", { name: "URL" })
|
||||
.locator("div")
|
||||
.first()
|
||||
.click();
|
||||
await page.getByRole("textbox", { name: "Type something..." }).click();
|
||||
await page
|
||||
.getByRole("textbox", { name: "Type something..." })
|
||||
.press("Control+a");
|
||||
await page.getByRole("textbox", { name: "Type something..." }).fill("teste");
|
||||
await page.getByRole("tab", { name: "cURL" }).click();
|
||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||
const handle2 = await page.evaluateHandle(() =>
|
||||
navigator.clipboard.readText()
|
||||
);
|
||||
const clipboardContent2 = await handle2.jsonValue();
|
||||
const newValue = clipboardContent2;
|
||||
expect(oldValue).not.toBe(newValue);
|
||||
expect(clipboardContent2.length).toBeGreaterThan(clipboardContent.length);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue