Merge branch 'main' into docs-publish-v0

This commit is contained in:
Mendon Kissling
2025-02-19 11:19:11 -05:00
committed by GitHub
76 changed files with 2783 additions and 1969 deletions

View File

@ -18,13 +18,13 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 18 node-version: 18
cache: npm cache: yarn
cache-dependency-path: ./docs/package-lock.json cache-dependency-path: ./docs/yarn.lock
- name: Install dependencies - name: Install dependencies
run: cd docs && npm install --legacy-peer-deps run: cd docs && yarn install
- name: Build website - name: Build website
run: cd docs && npm run build run: cd docs && yarn build
# Popular action to deploy to GitHub Pages: # Popular action to deploy to GitHub Pages:
# Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus # Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus

View File

@ -91,6 +91,21 @@ To access the **Logs** pane, click your **Flow Name**, and then select **Logs**.
![](/img/logs.png) ![](/img/logs.png)
Langflow stores logs at the location specified in the `LANGFLOW_CONFIG_DIR` environment variable.
This directory's default location depends on your operating system.
* **Linux/WSL**: `~/.cache/langflow/`
* **macOS**: `/Users/<username>/Library/Caches/langflow/`
* **Windows**: `%LOCALAPPDATA%\langflow\langflow\Cache`
To modify the location of your log file:
1. Add `LANGFLOW_LOG_FILE=path/to/logfile.log` in your `.env.` file.
2. To start Langflow with the values from your `.env` file, start Langflow with `uv run langflow run --env-file .env`.
An example `.env` file is available in the [project repository](https://github.com/langflow-ai/langflow/blob/main/.env.example).
## Projects and folders ## Projects and folders
The **My Projects** page displays all the flows and components you've created in the Langflow workspace. The **My Projects** page displays all the flows and components you've created in the Langflow workspace.

View File

@ -20,9 +20,6 @@ const config = {
projectName: "langflow", projectName: "langflow",
trailingSlash: false, trailingSlash: false,
staticDirectories: ["static"], staticDirectories: ["static"],
customFields: {
mendableAnonKey: "b7f52734-297c-41dc-8737-edbd13196394", // Mendable Anon Client-side key, safe to expose to the public
},
i18n: { i18n: {
defaultLocale: "en", defaultLocale: "en",
locales: ["en"], locales: ["en"],
@ -261,6 +258,15 @@ const config = {
hideable: false, hideable: false,
}, },
}, },
algolia: {
appId: 'UZK6BDPCVY',
// public key, safe to commit
apiKey: 'adbd7686dceb1cd510d5ce20d04bf74c',
indexName: 'langflow',
contextualSearch: true,
searchParameters: {},
searchPagePath: 'search',
},
}), }),
}; };

View File

@ -12,10 +12,10 @@
}, },
"dependencies": { "dependencies": {
"@code-hike/mdx": "^0.9.0", "@code-hike/mdx": "^0.9.0",
"@docusaurus/core": "^3.7.0", "@docusaurus/core": "3.7.0",
"@docusaurus/plugin-client-redirects": "^3.7.0", "@docusaurus/plugin-client-redirects": "^3.7.0",
"@docusaurus/plugin-google-tag-manager": "^3.7.0", "@docusaurus/plugin-google-tag-manager": "^3.7.0",
"@docusaurus/preset-classic": "^3.7.0", "@docusaurus/preset-classic": "3.7.0",
"@easyops-cn/docusaurus-search-local": "^0.45.0", "@easyops-cn/docusaurus-search-local": "^0.45.0",
"@mdx-js/react": "^3.0.1", "@mdx-js/react": "^3.0.1",
"@mendable/search": "^0.0.206", "@mendable/search": "^0.0.206",

View File

@ -1,52 +1,77 @@
import React from "react"; import React, { useState } from "react";
import Footer from "@theme-original/Footer"; import Footer from "@theme-original/Footer";
import { MendableFloatingButton } from "@mendable/search"; import { useDocSearchKeyboardEvents } from '@docsearch/react';
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
export default function FooterWrapper(props) { export default function FooterWrapper(props) {
const iconSpan1 = React.createElement( const [isHovered, setIsHovered] = useState(false);
"img", const searchButtonRef = React.useRef(null);
{
src: "/img/langflow-icon-black-transparent.svg",
srcDark: "",
style: { width: "40px" },
},
null
);
const icon = React.createElement( useDocSearchKeyboardEvents({
"div", isOpen: false,
{ onOpen: () => {
style: { searchButtonRef.current?.click();
color: "#000000",
fontSize: "22px",
width: "48px",
height: "48px",
margin: "0px",
padding: "0px",
display: "flex",
alignItems: "center",
justifyContent: "center",
textAlign: "center",
},
}, },
[iconSpan1]
);
const {
siteConfig: { customFields },
} = useDocusaurusContext();
const mendableFloatingButton = React.createElement(MendableFloatingButton, {
floatingButtonStyle: { color: "#000000", backgroundColor: "#f6f6f6" },
anon_key: customFields.mendableAnonKey,
showSimpleSearch: true,
icon: icon,
}); });
const searchButton = (
<div
ref={searchButtonRef}
onClick={() => {
// This will trigger Docusaurus's default search modal
document.querySelector('.DocSearch-Button')?.click();
}}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
style={{
position: 'fixed',
right: '20px',
bottom: '20px',
zIndex: 100,
display: 'flex',
alignItems: 'center',
gap: '10px',
cursor: 'pointer',
}}
>
{isHovered && (
<div
style={{
backgroundColor: "#f6f6f6",
padding: '8px 16px',
borderRadius: '20px',
color: '#000',
fontSize: '14px',
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
}}
>
Hi, how can I help you?
</div>
)}
<div
style={{
backgroundColor: "#f6f6f6",
borderRadius: "50%",
width: "48px",
height: "48px",
display: "flex",
alignItems: "center",
justifyContent: "center",
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
}}
>
<img
src="/img/langflow-icon-black-transparent.svg"
style={{ width: "40px" }}
alt="Search"
/>
</div>
</div>
);
return ( return (
<> <>
<Footer /> <Footer {...props} />
{mendableFloatingButton} {searchButton}
</> </>
); );
} }

View File

@ -1,23 +0,0 @@
// By default, the classic theme does not provide any SearchBar implementation
// If you swizzled this, it is your responsibility to provide an implementation
// Tip: swizzle the SearchBar from the Algolia theme for inspiration:
// npm run swizzle @docusaurus/theme-search-algolia SearchBar
import React from 'react'
import { MendableSearchBar } from '@mendable/search'
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
export default function SearchBarWrapper() {
const {
siteConfig: { customFields },
} = useDocusaurusContext()
return (
<div className="mendable-search">
<MendableSearchBar
anon_key={customFields.mendableAnonKey}
placeholder="Search..."
dialogPlaceholder="How to deploy my application?"
showSimpleSearch
/>
</div>
)
}

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ export class EcrRepository extends Construct {
super(scope, id) super(scope, id)
const imagePlatform = props.arch == ecs.CpuArchitecture.ARM64 ? Platform.LINUX_ARM64 : Platform.LINUX_AMD64 const imagePlatform = props.arch == ecs.CpuArchitecture.ARM64 ? Platform.LINUX_ARM64 : Platform.LINUX_AMD64
const backendPath = path.join(__dirname, "../../../../../", "langflow") const backendPath = path.join(__dirname, "../../../../", "docker")
const excludeDir = ['node_modules','.git', 'cdk.out'] const excludeDir = ['node_modules','.git', 'cdk.out']
const LifecycleRule = { const LifecycleRule = {
tagStatus: ecr.TagStatus.ANY, tagStatus: ecr.TagStatus.ANY,

View File

@ -22,7 +22,7 @@
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.12", "@types/jest": "^29.5.12",
"@types/node": "^20.12.12", "@types/node": "^20.12.12",
"aws-cdk": "^2.141.0", "aws-cdk": "^2.1000.2",
"jest": "^29.7.0", "jest": "^29.7.0",
"ts-jest": "^29.1.2", "ts-jest": "^29.1.2",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
@ -43,19 +43,49 @@
} }
}, },
"node_modules/@aws-cdk/asset-awscli-v1": { "node_modules/@aws-cdk/asset-awscli-v1": {
"version": "2.2.202", "version": "2.2.224",
"resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.202.tgz", "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.224.tgz",
"integrity": "sha512-JqlF0D4+EVugnG5dAsNZMqhu3HW7ehOXm5SDMxMbXNDMdsF0pxtQKNHRl52z1U9igsHmaFpUgSGjbhAJ+0JONg==" "integrity": "sha512-4CQP+y0rLq4IWzOlTqBhe8IxBU3Tul9KcmHxiAqztQRWLIl5HAVGCOWdLzHMLgbpFWNNMlIJxB8GwBEV0pWtfQ==",
}, "license": "Apache-2.0"
"node_modules/@aws-cdk/asset-kubectl-v20": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@aws-cdk/asset-kubectl-v20/-/asset-kubectl-v20-2.1.2.tgz",
"integrity": "sha512-3M2tELJOxQv0apCIiuKQ4pAbncz9GuLwnKFqxifWfe77wuMxyTRPmxssYHs42ePqzap1LT6GDcPygGs+hHstLg=="
}, },
"node_modules/@aws-cdk/asset-node-proxy-agent-v6": { "node_modules/@aws-cdk/asset-node-proxy-agent-v6": {
"version": "2.0.3", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.0.3.tgz", "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.0.tgz",
"integrity": "sha512-twhuEG+JPOYCYPx/xy5uH2+VUsIEhPTzDY0F1KuB+ocjWWB/KEDiOVL19nHvbPCB6fhWnkykXEMJ4HHcKvjtvg==" "integrity": "sha512-7bY3J8GCVxLupn/kNmpPc5VJz8grx+4RKfnnJiO1LG+uxkZfANZG3RMHhE+qQxxwkyQ9/MfPtTpf748UhR425A==",
"license": "Apache-2.0"
},
"node_modules/@aws-cdk/cloud-assembly-schema": {
"version": "39.2.20",
"resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-39.2.20.tgz",
"integrity": "sha512-RI7S8jphGA8mak154ElnEJQPNTTV4PZmA7jgqnBBHQGyOPJIXxtACubNQ5m4YgjpkK3UJHsWT+/cOAfM/Au/Wg==",
"bundleDependencies": [
"jsonschema",
"semver"
],
"license": "Apache-2.0",
"dependencies": {
"jsonschema": "~1.4.1",
"semver": "^7.7.1"
}
},
"node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": {
"version": "1.4.1",
"inBundle": true,
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": {
"version": "7.7.1",
"inBundle": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
}, },
"node_modules/@aws-cdk/integ-tests-alpha": { "node_modules/@aws-cdk/integ-tests-alpha": {
"version": "2.138.0-alpha.0", "version": "2.138.0-alpha.0",
@ -1451,24 +1481,25 @@
} }
}, },
"node_modules/aws-cdk": { "node_modules/aws-cdk": {
"version": "2.141.0", "version": "2.1000.2",
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.141.0.tgz", "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1000.2.tgz",
"integrity": "sha512-RM9uDiETBEKCHemItaRGVjOLwoZ5iqXnejpyXY7+YF75c2c0Ui7HSZI8QD0stDg3S/2UbLcKv2RA9dBsjrWUGA==", "integrity": "sha512-QsXqJhGWjHNqP7etgE3sHOTiDBXItmSKdFKgsm1qPMBabCMyFfmWZnEeUxfZ4sMaIoxvLpr3sqoWSNeLuUk4sg==",
"dev": true, "dev": true,
"license": "Apache-2.0",
"bin": { "bin": {
"cdk": "bin/cdk" "cdk": "bin/cdk"
}, },
"engines": { "engines": {
"node": ">= 14.15.0" "node": ">= 16.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"fsevents": "2.3.2" "fsevents": "2.3.2"
} }
}, },
"node_modules/aws-cdk-lib": { "node_modules/aws-cdk-lib": {
"version": "2.141.0", "version": "2.179.0",
"resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.141.0.tgz", "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.179.0.tgz",
"integrity": "sha512-xda56Lfwpdqg9MssnFdXrAKTmeeNjfrfFCaWwqGqToG6cfGY2W+6wyyoObX60/MeZGhhs3Lhdb/K94ulLJ4X/A==", "integrity": "sha512-fwkoEzvh3TXYj+GPkyq/GSQt63JJV1dBgDKwr3xRdb8lQaPntSclmisa+ARO8tjPfkru1NqxAFQTtiqtAE83cA==",
"bundleDependencies": [ "bundleDependencies": [
"@balena/dockerignore", "@balena/dockerignore",
"case", "case",
@ -1482,19 +1513,20 @@
"yaml", "yaml",
"mime-types" "mime-types"
], ],
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-cdk/asset-awscli-v1": "^2.2.202", "@aws-cdk/asset-awscli-v1": "^2.2.208",
"@aws-cdk/asset-kubectl-v20": "^2.1.2", "@aws-cdk/asset-node-proxy-agent-v6": "^2.1.0",
"@aws-cdk/asset-node-proxy-agent-v6": "^2.0.3", "@aws-cdk/cloud-assembly-schema": "^39.2.0",
"@balena/dockerignore": "^1.0.2", "@balena/dockerignore": "^1.0.2",
"case": "1.6.3", "case": "1.6.3",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"ignore": "^5.3.1", "ignore": "^5.3.2",
"jsonschema": "^1.4.1", "jsonschema": "^1.4.1",
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"minimatch": "^3.1.2", "minimatch": "^3.1.2",
"punycode": "^2.3.1", "punycode": "^2.3.1",
"semver": "^7.6.0", "semver": "^7.6.3",
"table": "^6.8.2", "table": "^6.8.2",
"yaml": "1.10.2" "yaml": "1.10.2"
}, },
@ -1511,14 +1543,14 @@
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/aws-cdk-lib/node_modules/ajv": { "node_modules/aws-cdk-lib/node_modules/ajv": {
"version": "8.13.0", "version": "8.17.1",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0", "json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2", "require-from-string": "^2.0.2"
"uri-js": "^4.4.1"
}, },
"funding": { "funding": {
"type": "github", "type": "github",
@ -1608,8 +1640,23 @@
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/aws-cdk-lib/node_modules/fast-uri": {
"version": "3.0.6",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"inBundle": true,
"license": "BSD-3-Clause"
},
"node_modules/aws-cdk-lib/node_modules/fs-extra": { "node_modules/aws-cdk-lib/node_modules/fs-extra": {
"version": "11.2.0", "version": "11.3.0",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1627,7 +1674,7 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/aws-cdk-lib/node_modules/ignore": { "node_modules/aws-cdk-lib/node_modules/ignore": {
"version": "5.3.1", "version": "5.3.2",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -1659,7 +1706,7 @@
} }
}, },
"node_modules/aws-cdk-lib/node_modules/jsonschema": { "node_modules/aws-cdk-lib/node_modules/jsonschema": {
"version": "1.4.1", "version": "1.5.0",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -1671,17 +1718,6 @@
"inBundle": true, "inBundle": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/aws-cdk-lib/node_modules/lru-cache": {
"version": "6.0.0",
"inBundle": true,
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/aws-cdk-lib/node_modules/mime-db": { "node_modules/aws-cdk-lib/node_modules/mime-db": {
"version": "1.52.0", "version": "1.52.0",
"inBundle": true, "inBundle": true,
@ -1729,12 +1765,9 @@
} }
}, },
"node_modules/aws-cdk-lib/node_modules/semver": { "node_modules/aws-cdk-lib/node_modules/semver": {
"version": "7.6.0", "version": "7.6.3",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
}, },
@ -1783,7 +1816,7 @@
} }
}, },
"node_modules/aws-cdk-lib/node_modules/table": { "node_modules/aws-cdk-lib/node_modules/table": {
"version": "6.8.2", "version": "6.9.0",
"inBundle": true, "inBundle": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
@ -1805,19 +1838,6 @@
"node": ">= 10.0.0" "node": ">= 10.0.0"
} }
}, },
"node_modules/aws-cdk-lib/node_modules/uri-js": {
"version": "4.4.1",
"inBundle": true,
"license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
}
},
"node_modules/aws-cdk-lib/node_modules/yallist": {
"version": "4.0.0",
"inBundle": true,
"license": "ISC"
},
"node_modules/aws-cdk-lib/node_modules/yaml": { "node_modules/aws-cdk-lib/node_modules/yaml": {
"version": "1.10.2", "version": "1.10.2",
"inBundle": true, "inBundle": true,
@ -2535,10 +2555,11 @@
"dev": true "dev": true
}, },
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"path-key": "^3.1.0", "path-key": "^3.1.0",
"shebang-command": "^2.0.0", "shebang-command": "^2.0.0",
@ -3837,12 +3858,13 @@
"dev": true "dev": true
}, },
"node_modules/micromatch": { "node_modules/micromatch": {
"version": "4.0.5", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"braces": "^3.0.2", "braces": "^3.0.3",
"picomatch": "^2.3.1" "picomatch": "^2.3.1"
}, },
"engines": { "engines": {

View File

@ -13,7 +13,7 @@
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.12", "@types/jest": "^29.5.12",
"@types/node": "^20.12.12", "@types/node": "^20.12.12",
"aws-cdk": "^2.141.0", "aws-cdk": "^2.1000.2",
"jest": "^29.7.0", "jest": "^29.7.0",
"ts-jest": "^29.1.2", "ts-jest": "^29.1.2",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",

View File

@ -19,6 +19,7 @@ from .openrouter import OpenRouterComponent
from .perplexity import PerplexityComponent from .perplexity import PerplexityComponent
from .sambanova import SambaNovaComponent from .sambanova import SambaNovaComponent
from .vertexai import ChatVertexAIComponent from .vertexai import ChatVertexAIComponent
from .xai import XAIModelComponent
__all__ = [ __all__ = [
"AIMLModelComponent", "AIMLModelComponent",
@ -42,4 +43,5 @@ __all__ = [
"PerplexityComponent", "PerplexityComponent",
"QianfanChatEndpointComponent", "QianfanChatEndpointComponent",
"SambaNovaComponent", "SambaNovaComponent",
"XAIModelComponent",
] ]

View File

@ -0,0 +1,155 @@
import requests
from langchain_openai import ChatOpenAI
from pydantic.v1 import SecretStr
from typing_extensions import override
from langflow.base.models.model import LCModelComponent
from langflow.field_typing import LanguageModel
from langflow.field_typing.range_spec import RangeSpec
from langflow.inputs import BoolInput, DictInput, DropdownInput, IntInput, MessageTextInput, SecretStrInput, SliderInput
XAI_DEFAULT_MODELS = ["grok-2-latest"]
class XAIModelComponent(LCModelComponent):
display_name = "xAI"
description = "Generates text using xAI models like Grok."
icon = "xAI"
name = "xAIModel"
inputs = [
*LCModelComponent._base_inputs,
IntInput(
name="max_tokens",
display_name="Max Tokens",
advanced=True,
info="The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
range_spec=RangeSpec(min=0, max=128000),
),
DictInput(
name="model_kwargs",
display_name="Model Kwargs",
advanced=True,
info="Additional keyword arguments to pass to the model.",
),
BoolInput(
name="json_mode",
display_name="JSON Mode",
advanced=True,
info="If True, it will output JSON regardless of passing a schema.",
),
DropdownInput(
name="model_name",
display_name="Model Name",
advanced=False,
options=XAI_DEFAULT_MODELS,
value=XAI_DEFAULT_MODELS[0],
refresh_button=True,
combobox=True,
info="The xAI model to use",
),
MessageTextInput(
name="base_url",
display_name="xAI API Base",
advanced=True,
info="The base URL of the xAI API. Defaults to https://api.x.ai/v1",
value="https://api.x.ai/v1",
),
SecretStrInput(
name="api_key",
display_name="xAI API Key",
info="The xAI API Key to use for the model.",
advanced=False,
value="XAI_API_KEY",
required=True,
),
SliderInput(
name="temperature", display_name="Temperature", value=0.1, range_spec=RangeSpec(min=0, max=2, step=0.01)
),
IntInput(
name="seed",
display_name="Seed",
info="The seed controls the reproducibility of the job.",
advanced=True,
value=1,
),
]
def get_models(self) -> list[str]:
"""Fetch available models from xAI API."""
if not self.api_key:
return XAI_DEFAULT_MODELS
base_url = self.base_url or "https://api.x.ai/v1"
url = f"{base_url}/language-models"
headers = {"Authorization": f"Bearer {self.api_key}", "Accept": "application/json"}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
# Extract model IDs and any aliases
models = set()
for model in data.get("models", []):
models.add(model["id"])
models.update(model.get("aliases", []))
return sorted(models) if models else XAI_DEFAULT_MODELS
except requests.RequestException as e:
self.status = f"Error fetching models: {e}"
return XAI_DEFAULT_MODELS
@override
def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):
"""Update build configuration with fresh model list when key fields change."""
if field_name in {"api_key", "base_url", "model_name"}:
models = self.get_models()
build_config["model_name"]["options"] = models
return build_config
def build_model(self) -> LanguageModel:
api_key = self.api_key
temperature = self.temperature
model_name: str = self.model_name
max_tokens = self.max_tokens
model_kwargs = self.model_kwargs or {}
base_url = self.base_url or "https://api.x.ai/v1"
json_mode = self.json_mode
seed = self.seed
api_key = SecretStr(api_key).get_secret_value() if api_key else None
output = ChatOpenAI(
max_tokens=max_tokens or None,
model_kwargs=model_kwargs,
model=model_name,
base_url=base_url,
api_key=api_key,
temperature=temperature if temperature is not None else 0.1,
seed=seed,
)
if json_mode:
output = output.bind(response_format={"type": "json_object"})
return output
def _get_exception_message(self, e: Exception):
"""Get a message from an xAI exception.
Args:
e (Exception): The exception to get the message from.
Returns:
str: The message from the exception.
"""
try:
from openai import BadRequestError
except ImportError:
return None
if isinstance(e, BadRequestError):
message = e.body.get("message")
if message:
return message
return None

View File

@ -82,6 +82,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
"new_collection_name", "new_collection_name",
"embedding_generation_provider", "embedding_generation_provider",
"embedding_generation_model", "embedding_generation_model",
"dimension",
], ],
"template": { "template": {
"new_collection_name": StrInput( "new_collection_name": StrInput(
@ -330,7 +331,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
embedding_generation_model: str | None = None, embedding_generation_model: str | None = None,
): ):
# Create the data API client # Create the data API client
client = DataAPIClient(token=token) client = DataAPIClient(token=token, environment=environment)
# Get the database object # Get the database object
database = client.get_async_database(api_endpoint=api_endpoint, token=token) database = client.get_async_database(api_endpoint=api_endpoint, token=token)
@ -554,6 +555,9 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
api_endpoint=build_config["api_endpoint"]["value"], api_endpoint=build_config["api_endpoint"]["value"],
) )
# Append a special case for Bring your own
vectorize_providers["Bring your own"] = [None, ["Bring your own"]]
# If the collection is set, allow user to see embedding options # If the collection is set, allow user to see embedding options
build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][ build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
"embedding_generation_provider" "embedding_generation_provider"
@ -714,7 +718,11 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
generation_provider = field_value["embedding_generation_provider"] generation_provider = field_value["embedding_generation_provider"]
provider = generation_provider if generation_provider != "Bring your own" else None provider = generation_provider if generation_provider != "Bring your own" else None
generation_model = field_value["embedding_generation_model"] generation_model = field_value["embedding_generation_model"]
model = generation_model if generation_model else None model = generation_model if generation_model and generation_model != "Bring your own" else None
# Set the embedding choice
build_config["embedding_choice"]["value"] = "Astra Vectorize" if provider else "Embedding Model"
build_config["embedding_model"]["advanced"] = bool(provider)
# Add the new collection to the list of options # Add the new collection to the list of options
icon = "NVIDIA" if provider == "Nvidia" else "vectorstores" icon = "NVIDIA" if provider == "Nvidia" else "vectorstores"
@ -788,6 +796,10 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
# Ensure that autodetect collection is set to False, since its a new collection # Ensure that autodetect collection is set to False, since its a new collection
build_config["autodetect_collection"]["value"] = False build_config["autodetect_collection"]["value"] = False
# If nothing is selected, can't detect provider - return
if not field_value:
return build_config
# Find the position of the selected collection to align with metadata # Find the position of the selected collection to align with metadata
index_of_name = build_config["collection_name"]["options"].index(field_value) index_of_name = build_config["collection_name"]["options"].index(field_value)
value_of_provider = build_config["collection_name"]["options_metadata"][index_of_name]["provider"] value_of_provider = build_config["collection_name"]["options_metadata"][index_of_name]["provider"]

View File

@ -960,7 +960,9 @@
"key": "ParseData", "key": "ParseData",
"legacy": false, "legacy": false,
"lf_version": "1.1.5", "lf_version": "1.1.5",
"metadata": {}, "metadata": {
"legacy_name": "Parse Data"
},
"minimized": false, "minimized": false,
"output_types": [], "output_types": [],
"outputs": [ "outputs": [
@ -1011,7 +1013,7 @@
"show": true, "show": true,
"title_case": false, "title_case": false,
"type": "code", "type": "code",
"value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n" "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
}, },
"data": { "data": {
"_input_type": "DataInput", "_input_type": "DataInput",

View File

@ -452,7 +452,9 @@
"icon": "message-square", "icon": "message-square",
"legacy": false, "legacy": false,
"lf_version": "1.1.5", "lf_version": "1.1.5",
"metadata": {}, "metadata": {
"legacy_name": "Parse Data"
},
"minimized": false, "minimized": false,
"output_types": [], "output_types": [],
"outputs": [ "outputs": [
@ -502,7 +504,7 @@
"show": true, "show": true,
"title_case": false, "title_case": false,
"type": "code", "type": "code",
"value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n" "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
}, },
"data": { "data": {
"_input_type": "DataInput", "_input_type": "DataInput",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -124,6 +124,15 @@ class DatabaseService(Service):
# if the user specifies an empty dict, we allow it. # if the user specifies an empty dict, we allow it.
kwargs = self._build_connection_kwargs() kwargs = self._build_connection_kwargs()
poolclass_key = kwargs.get("poolclass")
if poolclass_key is not None:
pool_class = getattr(sa, poolclass_key, None)
if pool_class and isinstance(pool_class(), sa.pool.Pool):
logger.debug(f"Using poolclass: {poolclass_key}.")
kwargs["poolclass"] = pool_class
else:
logger.error(f"Invalid poolclass '{poolclass_key}' specified. Using default pool class.")
return create_async_engine( return create_async_engine(
self.database_url, self.database_url,
connect_args=self._get_connect_args(), connect_args=self._get_connect_args(),
@ -136,16 +145,18 @@ class DatabaseService(Service):
return self._create_engine() return self._create_engine()
def _get_connect_args(self): def _get_connect_args(self):
if self.settings_service.settings.database_url and self.settings_service.settings.database_url.startswith( settings = self.settings_service.settings
"sqlite"
): if settings.db_driver_connection_settings is not None:
connect_args = { return settings.db_driver_connection_settings
if settings.database_url and settings.database_url.startswith("sqlite"):
return {
"check_same_thread": False, "check_same_thread": False,
"timeout": self.settings_service.settings.db_connect_timeout, "timeout": settings.db_connect_timeout,
} }
else:
connect_args = {} return {}
return connect_args
def on_connection(self, dbapi_connection, _connection_record) -> None: def on_connection(self, dbapi_connection, _connection_record) -> None:
if isinstance(dbapi_connection, sqlite3.Connection | dialect_sqlite.aiosqlite.AsyncAdapt_aiosqlite_connection): if isinstance(dbapi_connection, sqlite3.Connection | dialect_sqlite.aiosqlite.AsyncAdapt_aiosqlite_connection):

View File

@ -90,6 +90,9 @@ class Settings(BaseSettings):
sqlite_pragmas: dict | None = {"synchronous": "NORMAL", "journal_mode": "WAL"} sqlite_pragmas: dict | None = {"synchronous": "NORMAL", "journal_mode": "WAL"}
"""SQLite pragmas to use when connecting to the database.""" """SQLite pragmas to use when connecting to the database."""
db_driver_connection_settings: dict | None = None
"""Database driver connection settings."""
db_connection_settings: dict | None = { db_connection_settings: dict | None = {
"pool_size": 20, # Match the pool_size above "pool_size": 20, # Match the pool_size above
"max_overflow": 30, # Match the max_overflow above "max_overflow": 30, # Match the max_overflow above

View File

@ -0,0 +1,198 @@
from unittest.mock import MagicMock, patch
import pytest
from langflow.components.models import XAIModelComponent
from langflow.custom import Component
from langflow.custom.utils import build_custom_component_template
from langflow.inputs import (
BoolInput,
DictInput,
DropdownInput,
IntInput,
MessageTextInput,
SecretStrInput,
SliderInput,
)
from tests.base import ComponentTestBaseWithoutClient
class TestXAIComponent(ComponentTestBaseWithoutClient):
@pytest.fixture
def component_class(self):
return XAIModelComponent
@pytest.fixture
def default_kwargs(self):
return {
"temperature": 0.1,
"max_tokens": 50,
"api_key": "dummy-key",
"model_name": "grok-2-latest",
"model_kwargs": {},
"base_url": "https://api.x.ai/v1",
"seed": 42,
}
@pytest.fixture
def file_names_mapping(self):
return []
def test_initialization(self, component_class):
component = component_class()
assert component.display_name == "xAI"
assert component.description == "Generates text using xAI models like Grok."
assert component.icon == "xAI"
assert component.name == "xAIModel"
def test_template(self, default_kwargs):
component = XAIModelComponent(**default_kwargs)
comp = Component(_code=component._code)
frontend_node, _ = build_custom_component_template(comp)
assert isinstance(frontend_node, dict)
assert "template" in frontend_node
input_names = [inp["name"] for inp in frontend_node["template"].values() if isinstance(inp, dict)]
expected_inputs = [
"max_tokens",
"model_kwargs",
"json_mode",
"model_name",
"base_url",
"api_key",
"temperature",
"seed",
]
for input_name in expected_inputs:
assert input_name in input_names
def test_inputs(self):
component = XAIModelComponent()
inputs = component.inputs
expected_inputs = {
"max_tokens": IntInput,
"model_kwargs": DictInput,
"json_mode": BoolInput,
"model_name": DropdownInput,
"base_url": MessageTextInput,
"api_key": SecretStrInput,
"temperature": SliderInput,
"seed": IntInput,
}
for name, input_type in expected_inputs.items():
matching_inputs = [inp for inp in inputs if isinstance(inp, input_type) and inp.name == name]
assert matching_inputs, f"Missing or incorrect input: {name}"
if name == "model_name":
input_field = matching_inputs[0]
assert input_field.value == "grok-2-latest"
assert input_field.refresh_button is True
elif name == "temperature":
input_field = matching_inputs[0]
assert input_field.value == 0.1
assert input_field.range_spec.min == 0
assert input_field.range_spec.max == 2
def test_build_model(self, component_class, default_kwargs, mocker):
component = component_class(**default_kwargs)
component.temperature = 0.7
component.max_tokens = 100
component.api_key = "test-key"
component.model_name = "grok-2-latest"
component.model_kwargs = {}
component.base_url = "https://api.x.ai/v1"
component.seed = 1
mock_chat_openai = mocker.patch("langflow.components.models.xai.ChatOpenAI", return_value=MagicMock())
model = component.build_model()
mock_chat_openai.assert_called_once_with(
max_tokens=100,
model_kwargs={},
model="grok-2-latest",
base_url="https://api.x.ai/v1",
api_key="test-key",
temperature=0.7,
seed=1,
)
assert model == mock_chat_openai.return_value
def test_get_models(self):
component = XAIModelComponent()
with patch("requests.get") as mock_get:
mock_response = MagicMock()
mock_response.json.return_value = {
"models": [
{"id": "grok-2-latest", "aliases": ["grok-2"]},
{"id": "grok-1", "aliases": []},
]
}
mock_get.return_value = mock_response
component.api_key = "test-key"
models = component.get_models()
assert sorted(models) == ["grok-1", "grok-2", "grok-2-latest"]
mock_get.assert_called_once_with(
"https://api.x.ai/v1/language-models",
headers={
"Authorization": "Bearer test-key",
"Accept": "application/json",
},
timeout=10,
)
def test_get_models_no_api_key(self):
component = XAIModelComponent(api_key=None)
models = component.get_models()
assert models == ["grok-2-latest"]
def test_build_model_error(self, component_class, mocker):
from openai import BadRequestError
component = component_class()
component.api_key = "invalid-key"
component.model_name = "grok-2-latest"
component.temperature = 0.7
component.max_tokens = 100
component.model_kwargs = {}
component.base_url = "https://api.x.ai/v1"
component.seed = 1
mocker.patch(
"langflow.components.models.xai.ChatOpenAI",
side_effect=BadRequestError(
message="Invalid API key",
response=MagicMock(),
body={"message": "Invalid API key provided"},
),
)
with pytest.raises(BadRequestError) as exc_info:
component.build_model()
assert exc_info.value.body["message"] == "Invalid API key provided"
def test_json_mode(self, component_class, mocker):
component = component_class()
component.api_key = "test-key"
component.json_mode = True
component.temperature = 0.7
component.max_tokens = 100
component.model_name = "grok-2-latest"
component.model_kwargs = {}
component.base_url = "https://api.x.ai/v1"
component.seed = 1
mock_instance = MagicMock()
mock_bound_instance = MagicMock()
mock_instance.bind.return_value = mock_bound_instance
mocker.patch("langflow.components.models.xai.ChatOpenAI", return_value=mock_instance)
model = component.build_model()
mock_instance.bind.assert_called_once_with(response_format={"type": "json_object"})
assert model == mock_bound_instance
def test_update_build_config(self):
component = XAIModelComponent()
build_config = {"model_name": {"options": []}}
updated_config = component.update_build_config(build_config, "test-key", "api_key")
assert "model_name" in updated_config
updated_config = component.update_build_config(build_config, "grok-2-latest", "model_name")
assert "model_name" in updated_config

View File

@ -1,4 +1,4 @@
import React, { useMemo } from "react"; import { useMemo } from "react";
import { getNodeOutputColors } from "../../../helpers/get-node-output-colors"; import { getNodeOutputColors } from "../../../helpers/get-node-output-colors";
import { getNodeOutputColorsName } from "../../../helpers/get-node-output-colors-name"; import { getNodeOutputColorsName } from "../../../helpers/get-node-output-colors-name";

View File

@ -1,9 +1,6 @@
import ForwardedIconComponent from "../../components/common/genericIconComponent"; import ForwardedIconComponent from "../../components/common/genericIconComponent";
import Checkmark from "../../components/ui/checkmark";
import Loading from "../../components/ui/loading";
import Xmark from "../../components/ui/xmark"; import Xmark from "../../components/ui/xmark";
import { BuildStatus } from "../../constants/enums"; import { BuildStatus } from "../../constants/enums";
import { VertexBuildTypeAPI } from "../../types/api";
const useIconStatus = (buildStatus: BuildStatus | undefined) => { const useIconStatus = (buildStatus: BuildStatus | undefined) => {
const conditionError = buildStatus === BuildStatus.ERROR; const conditionError = buildStatus === BuildStatus.ERROR;

View File

@ -18,7 +18,6 @@ import {
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "../../ui/card"; } from "../../ui/card";
import Loading from "../../ui/loading";
import IconComponent from "../genericIconComponent"; import IconComponent from "../genericIconComponent";
import ShadTooltip from "../shadTooltipComponent"; import ShadTooltip from "../shadTooltipComponent";
import useDataEffect from "./hooks/use-data-effect"; import useDataEffect from "./hooks/use-data-effect";

View File

@ -1,7 +1,6 @@
import BaseModal from "../../../modals/baseModal"; import BaseModal from "../../../modals/baseModal";
import { fetchErrorComponentType } from "../../../types/components"; import { fetchErrorComponentType } from "../../../types/components";
import Loading from "../../ui/loading"; import Loading from "../../ui/loading";
import IconComponent from "../genericIconComponent";
export default function TimeoutErrorComponent({ export default function TimeoutErrorComponent({
message, message,

View File

@ -1,4 +1,3 @@
import ForwardedIconComponent from "@/components/common/genericIconComponent";
import { useLogout } from "@/controllers/API/queries/auth"; import { useLogout } from "@/controllers/API/queries/auth";
import { CustomFeedbackDialog } from "@/customization/components/custom-feedback-dialog"; import { CustomFeedbackDialog } from "@/customization/components/custom-feedback-dialog";
import { CustomHeaderMenuItemsTitle } from "@/customization/components/custom-header-menu-items-title"; import { CustomHeaderMenuItemsTitle } from "@/customization/components/custom-header-menu-items-title";

View File

@ -1,5 +1,4 @@
import { FlowType } from "@/types/flow"; import { FlowType } from "@/types/flow";
import { storeComponent } from "../../../../../types/store";
import { cn } from "../../../../../utils/utils"; import { cn } from "../../../../../utils/utils";
import ForwardedIconComponent from "../../../../common/genericIconComponent"; import ForwardedIconComponent from "../../../../common/genericIconComponent";
import { Card, CardHeader, CardTitle } from "../../../../ui/card"; import { Card, CardHeader, CardTitle } from "../../../../ui/card";

View File

@ -2,7 +2,6 @@ import { FlowType } from "@/types/flow";
import { useCallback } from "react"; import { useCallback } from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore"; import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
import { storeComponent } from "../../../../types/store";
import DragCardComponent from "../components/dragCardComponent"; import DragCardComponent from "../components/dragCardComponent";
const useDragStart = (data: FlowType) => { const useDragStart = (data: FlowType) => {

View File

@ -8,7 +8,6 @@ import { getInputsAndOutputs } from "../../../utils/storeUtils";
import { cn } from "../../../utils/utils"; import { cn } from "../../../utils/utils";
import IconComponent from "../../common/genericIconComponent"; import IconComponent from "../../common/genericIconComponent";
import ShadTooltip from "../../common/shadTooltipComponent"; import ShadTooltip from "../../common/shadTooltipComponent";
import { Button } from "../../ui/button";
import { import {
Card, Card,
CardDescription, CardDescription,

View File

@ -1,7 +1,6 @@
import { useState } from "react"; import { useState } from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { tomorrow } from "react-syntax-highlighter/dist/cjs/styles/prism"; import { tomorrow } from "react-syntax-highlighter/dist/cjs/styles/prism";
import { useDarkStore } from "../../../stores/darkStore";
import IconComponent from "../../common/genericIconComponent"; import IconComponent from "../../common/genericIconComponent";
import { Button } from "../../ui/button"; import { Button } from "../../ui/button";

View File

@ -65,10 +65,12 @@ export default function TableNodeComponent({
}; };
}, []); }, []);
const [selectedNodes, setSelectedNodes] = useState<Array<any>>([]); const [selectedNodes, setSelectedNodes] = useState<Array<any>>([]);
const [tempValue, setTempValue] = useState<any[]>(cloneDeep(value));
const [isModalOpen, setIsModalOpen] = useState(false);
const agGrid = useRef<AgGridReact>(null); const agGrid = useRef<AgGridReact>(null);
const componentColumns = columns const componentColumns = columns
? columns ? columns
: generateBackendColumnsFromValue(value ?? [], table_options); : generateBackendColumnsFromValue(tempValue ?? [], table_options);
let AgColumns = FormatColumns(componentColumns); let AgColumns = FormatColumns(componentColumns);
// add info to each column // add info to each column
AgColumns = AgColumns.map((col) => { AgColumns = AgColumns.map((col) => {
@ -93,7 +95,7 @@ export default function TableNodeComponent({
if (agGrid.current && !agGrid.current.api.isDestroyed()) { if (agGrid.current && !agGrid.current.api.isDestroyed()) {
const rows: any = []; const rows: any = [];
agGrid.current.api.forEachNode((node) => rows.push(node.data)); agGrid.current.api.forEachNode((node) => rows.push(node.data));
handleOnNewValue({ value: rows }); setTempValue(rows);
} }
} }
function deleteRow() { function deleteRow() {
@ -109,8 +111,7 @@ export default function TableNodeComponent({
if (agGrid.current && selectedNodes.length > 0) { if (agGrid.current && selectedNodes.length > 0) {
const toDuplicate = selectedNodes.map((node) => cloneDeep(node.data)); const toDuplicate = selectedNodes.map((node) => cloneDeep(node.data));
setSelectedNodes([]); setSelectedNodes([]);
const rows: any = []; setTempValue([...tempValue, ...toDuplicate]);
handleOnNewValue({ value: [...value, ...toDuplicate] });
} }
} }
function addRow() { function addRow() {
@ -118,12 +119,23 @@ export default function TableNodeComponent({
componentColumns.forEach((column) => { componentColumns.forEach((column) => {
newRow[column.name] = column.default ?? null; // Use the default value if available newRow[column.name] = column.default ?? null; // Use the default value if available
}); });
handleOnNewValue({ value: [...value, newRow] }); setTempValue([...tempValue, newRow]);
} }
function updateComponent() { function updateComponent() {
setAllRows(); setAllRows();
} }
function handleSave() {
handleOnNewValue({ value: tempValue });
setIsModalOpen(false);
}
function handleCancel() {
setTempValue(cloneDeep(value));
setIsModalOpen(false);
}
const editable = componentColumns const editable = componentColumns
.map((column) => { .map((column) => {
const isCustomEdit = const isCustomEdit =
@ -149,6 +161,8 @@ export default function TableNodeComponent({
> >
<div className="flex w-full items-center gap-3" data-testid={"div-" + id}> <div className="flex w-full items-center gap-3" data-testid={"div-" + id}>
<TableModal <TableModal
open={isModalOpen}
setOpen={setIsModalOpen}
stopEditingWhenCellsLoseFocus={true} stopEditingWhenCellsLoseFocus={true}
tableIcon={table_icon} tableIcon={table_icon}
tableOptions={table_options} tableOptions={table_options}
@ -169,8 +183,10 @@ export default function TableNodeComponent({
displayEmptyAlert={false} displayEmptyAlert={false}
className="h-full w-full" className="h-full w-full"
columnDefs={AgColumns} columnDefs={AgColumns}
rowData={value} rowData={tempValue}
context={{ field_parsers: table_options?.field_parsers }} context={{ field_parsers: table_options?.field_parsers }}
onSave={handleSave}
onCancel={handleCancel}
> >
<Button <Button
disabled={disabled} disabled={disabled}

View File

@ -4,7 +4,6 @@ import { useCallback, useEffect, useRef, useState } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "../../../../ui/input"; import { Input } from "../../../../ui/input";
import { ButtonInputList } from "./components/button-input-list"; import { ButtonInputList } from "./components/button-input-list";
import { DropdownMenuInputList } from "./components/dropdown-menu";
import { GRADIENT_CLASS } from "@/constants/constants"; import { GRADIENT_CLASS } from "@/constants/constants";
import { cn } from "../../../../../utils/utils"; import { cn } from "../../../../../utils/utils";

View File

@ -7,7 +7,7 @@ import {
} from "@/utils/reactflowUtils"; } from "@/utils/reactflowUtils";
import { cn } from "@/utils/utils"; import { cn } from "@/utils/utils";
import { cloneDeep } from "lodash"; import { cloneDeep } from "lodash";
import React, { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import IconComponent from "../../../../common/genericIconComponent"; import IconComponent from "../../../../common/genericIconComponent";
const KeypairListComponent = ({ const KeypairListComponent = ({

View File

@ -1,4 +1,3 @@
import { PopoverAnchor } from "@radix-ui/react-popover";
import Fuse from "fuse.js"; import Fuse from "fuse.js";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { cn } from "../../../../../utils/utils"; import { cn } from "../../../../../utils/utils";

View File

@ -13,7 +13,6 @@ import {
memo, memo,
useCallback, useCallback,
useContext, useContext,
useEffect,
useId, useId,
useMemo, useMemo,
} from "react"; } from "react";

View File

@ -6,7 +6,7 @@ import {
TargetAndTransition, TargetAndTransition,
Variants, Variants,
} from "framer-motion"; } from "framer-motion";
import React, { ReactElement } from "react"; import React from "react";
type PresetType = "blur" | "shake" | "scale" | "fade" | "slide"; type PresetType = "blur" | "shake" | "scale" | "fade" | "slide";

View File

@ -3,13 +3,11 @@ import { AxiosRequestConfig, AxiosResponse } from "axios";
import { BASE_URL_API } from "../../constants/constants"; import { BASE_URL_API } from "../../constants/constants";
import { api } from "../../controllers/API/api"; import { api } from "../../controllers/API/api";
import { import {
Component,
VertexBuildTypeAPI, VertexBuildTypeAPI,
VerticesOrderTypeAPI, VerticesOrderTypeAPI,
} from "../../types/api/index"; } from "../../types/api/index";
import { FlowStyleType, FlowType } from "../../types/flow"; import { FlowStyleType, FlowType } from "../../types/flow";
import { StoreComponentResponse } from "../../types/store"; import { StoreComponentResponse } from "../../types/store";
import { FlowPoolType } from "../../types/zustand/flow";
const GITHUB_API_URL = "https://api.github.com"; const GITHUB_API_URL = "https://api.github.com";

View File

@ -1,8 +1,4 @@
import { import { resetPasswordType, useMutationFunctionType } from "@/types/api";
changeUser,
resetPasswordType,
useMutationFunctionType,
} from "@/types/api";
import { UseMutationResult } from "@tanstack/react-query"; import { UseMutationResult } from "@tanstack/react-query";
import { api } from "../../api"; import { api } from "../../api";
import { getURL } from "../../helpers/constants"; import { getURL } from "../../helpers/constants";

View File

@ -1,4 +1,4 @@
import { LoginType, changeUser, useMutationFunctionType } from "@/types/api"; import { LoginType, useMutationFunctionType } from "@/types/api";
import { UseMutationResult } from "@tanstack/react-query"; import { UseMutationResult } from "@tanstack/react-query";
import { api } from "../../api"; import { api } from "../../api";
import { getURL } from "../../helpers/constants"; import { getURL } from "../../helpers/constants";

View File

@ -1,9 +1,4 @@
import { keepPreviousData } from "@tanstack/react-query"; import { useMutationFunctionType } from "../../../../types/api";
import {
useMutationFunctionType,
useQueryFunctionType,
} from "../../../../types/api";
import { api } from "../../api";
import { getURL } from "../../helpers/constants"; import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor"; import { UseRequestProcessor } from "../../services/request-processor";

View File

@ -2,7 +2,7 @@ import { useGlobalVariablesStore } from "@/stores/globalVariablesStore/globalVar
import getUnavailableFields from "@/stores/globalVariablesStore/utils/get-unavailable-fields"; import getUnavailableFields from "@/stores/globalVariablesStore/utils/get-unavailable-fields";
import { useMutationFunctionType } from "@/types/api"; import { useMutationFunctionType } from "@/types/api";
import { GlobalVariable } from "@/types/global_variables"; import { GlobalVariable } from "@/types/global_variables";
import { UseMutationOptions, UseMutationResult } from "@tanstack/react-query"; import { UseMutationResult } from "@tanstack/react-query";
import { api } from "../../api"; import { api } from "../../api";
import { getURL } from "../../helpers/constants"; import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor"; import { UseRequestProcessor } from "../../services/request-processor";

View File

@ -1,5 +1,4 @@
import { useMutationFunctionType } from "@/types/api"; import { useMutationFunctionType } from "@/types/api";
import { GlobalVariable } from "@/types/global_variables";
import { UseMutationResult } from "@tanstack/react-query"; import { UseMutationResult } from "@tanstack/react-query";
import { api } from "../../api"; import { api } from "../../api";
import { getURL } from "../../helpers/constants"; import { getURL } from "../../helpers/constants";

View File

@ -1,4 +1,3 @@
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
import { createFileUpload } from "@/helpers/create-file-upload"; import { createFileUpload } from "@/helpers/create-file-upload";
import { getObjectsFromFilelist } from "@/helpers/get-objects-from-filelist"; import { getObjectsFromFilelist } from "@/helpers/get-objects-from-filelist";
import useFlowStore from "@/stores/flowStore"; import useFlowStore from "@/stores/flowStore";

View File

@ -1,5 +1,3 @@
import React from "react";
const ArXivIcon = (props) => { const ArXivIcon = (props) => {
return ( return (
<svg <svg

View File

@ -1,5 +1,3 @@
import React from "react";
const UpstashIcon = (props) => ( const UpstashIcon = (props) => (
<svg <svg
width="256px" width="256px"

View File

@ -1,5 +1,3 @@
import React from "react";
const YouTubeIcon = (props) => ( const YouTubeIcon = (props) => (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

View File

@ -0,0 +1,10 @@
import { useDarkStore } from "@/stores/darkStore";
import React, { forwardRef } from "react";
import XAISVG from "./xAIIcon.jsx";
export const XAIIcon = forwardRef<SVGSVGElement, React.PropsWithChildren<{}>>(
(props, ref) => {
const isdark = useDarkStore((state) => state.dark).toString();
return <XAISVG ref={ref} isdark={isdark} {...props} />;
},
);

View File

@ -0,0 +1,19 @@
import { stringToBool } from "@/utils/utils";
const XAISVG = (props) => (
<svg
{...props}
fill={stringToBool(props.isdark) ? "#ffffff" : "#0A0A0A"}
fillRule="evenodd"
height="1em"
style={{ flex: "none", lineHeight: 1 }}
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<title>Grok</title>
<path d="M6.469 8.776L16.512 23h-4.464L2.005 8.776H6.47zm-.004 7.9l2.233 3.164L6.467 23H2l4.465-6.324zM22 2.582V23h-3.659V7.764L22 2.582zM22 1l-9.952 14.095-2.233-3.163L17.533 1H22z" />
</svg>
);
export default XAISVG;

View File

@ -0,0 +1 @@
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Grok</title><path d="M6.469 8.776L16.512 23h-4.464L2.005 8.776H6.47zm-.004 7.9l2.233 3.164L6.467 23H2l4.465-6.324zM22 2.582V23h-3.659V7.764L22 2.582zM22 1l-9.952 14.095-2.233-3.163L17.533 1H22z"></path></svg>

After

Width:  |  Height:  |  Size: 372 B

View File

@ -5,7 +5,7 @@ import useFileSizeValidator from "@/shared/hooks/use-file-size-validator";
import useAlertStore from "@/stores/alertStore"; import useAlertStore from "@/stores/alertStore";
import useFlowStore from "@/stores/flowStore"; import useFlowStore from "@/stores/flowStore";
import { useUtilityStore } from "@/stores/utilityStore"; import { useUtilityStore } from "@/stores/utilityStore";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef } from "react";
import ShortUniqueId from "short-unique-id"; import ShortUniqueId from "short-unique-id";
import { import {
ALLOWED_IMAGE_INPUT_EXTENSIONS, ALLOWED_IMAGE_INPUT_EXTENSIONS,

View File

@ -1,4 +1,3 @@
import { useState } from "react";
import IconComponent, { import IconComponent, {
ForwardedIconComponent, ForwardedIconComponent,
} from "../../../../../../components/common/genericIconComponent"; } from "../../../../../../components/common/genericIconComponent";

View File

@ -10,7 +10,6 @@ import JsonView from "react18-json-view";
import "react18-json-view/src/dark.css"; import "react18-json-view/src/dark.css";
import "react18-json-view/src/style.css"; import "react18-json-view/src/style.css";
import IconComponent from "../../components/common/genericIconComponent"; import IconComponent from "../../components/common/genericIconComponent";
import { CODE_DICT_DIALOG_SUBTITLE } from "../../constants/constants";
import { useDarkStore } from "../../stores/darkStore"; import { useDarkStore } from "../../stores/darkStore";
import BaseModal from "../baseModal"; import BaseModal from "../baseModal";

View File

@ -1,7 +1,6 @@
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { track } from "../../../../customization/utils/analytics"; import { track } from "../../../../customization/utils/analytics";
import useAddFlow from "../../../../hooks/flows/use-add-flow"; import useAddFlow from "../../../../hooks/flows/use-add-flow";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
import { FlowType } from "../../../../types/flow"; import { FlowType } from "../../../../types/flow";
import { updateIds } from "../../../../utils/reactflowUtils"; import { updateIds } from "../../../../utils/reactflowUtils";

View File

@ -18,7 +18,6 @@ import {
} from "../../../../components/ui/card"; } from "../../../../components/ui/card";
import { useFolderStore } from "../../../../stores/foldersStore"; import { useFolderStore } from "../../../../stores/foldersStore";
import { UndrawCardComponentProps } from "../../../../types/components"; import { UndrawCardComponentProps } from "../../../../types/components";
import { updateIds } from "../../../../utils/reactflowUtils";
import { useFlowCardClick } from "../hooks/use-redirect-flow-card-click"; import { useFlowCardClick } from "../hooks/use-redirect-flow-card-click";
export default function UndrawCardComponent({ export default function UndrawCardComponent({

View File

@ -15,6 +15,10 @@ interface TableModalProps extends TableComponentProps {
tableOptions?: TableOptionsTypeAPI; tableOptions?: TableOptionsTypeAPI;
hideColumns?: boolean | string[]; hideColumns?: boolean | string[];
tableIcon?: string; tableIcon?: string;
open?: boolean;
setOpen?: (open: boolean) => void;
onSave?: () => void;
onCancel?: () => void;
} }
const TableModal = forwardRef<AgGridReact, TableModalProps>( const TableModal = forwardRef<AgGridReact, TableModalProps>(
@ -25,22 +29,43 @@ const TableModal = forwardRef<AgGridReact, TableModalProps>(
children, children,
disabled, disabled,
tableIcon, tableIcon,
open,
setOpen,
onSave,
onCancel,
...props ...props
}: TableModalProps, }: TableModalProps,
ref: ForwardedRef<AgGridReact>, ref: ForwardedRef<AgGridReact>,
) => { ) => {
const handleSetOpen = (newOpen: boolean) => {
if (!newOpen && onCancel) {
onCancel();
}
if (setOpen) {
setOpen(newOpen);
}
};
const handleOnEscapeKeyDown = (e: KeyboardEvent) => {
const editingCells = (
ref as React.RefObject<AgGridReact>
)?.current?.api?.getEditingCells();
if (editingCells && editingCells.length > 0) {
e.preventDefault();
}
};
return ( return (
<BaseModal <BaseModal
onEscapeKeyDown={(e) => { onEscapeKeyDown={(e) => {
if ( handleOnEscapeKeyDown(e);
(
ref as React.RefObject<AgGridReact>
)?.current?.api.getEditingCells().length
) {
e.preventDefault();
}
}} }}
disable={disabled} disable={disabled}
open={open}
setOpen={(newOpen) => {
handleSetOpen(newOpen);
}}
> >
<BaseModal.Trigger asChild>{children}</BaseModal.Trigger> <BaseModal.Trigger asChild>{children}</BaseModal.Trigger>
<BaseModal.Header <BaseModal.Header
@ -59,6 +84,9 @@ const TableModal = forwardRef<AgGridReact, TableModalProps>(
{...props} {...props}
></TableComponent> ></TableComponent>
</BaseModal.Content> </BaseModal.Content>
<BaseModal.Footer
submit={onSave ? { label: "Save", onClick: onSave } : undefined}
></BaseModal.Footer>
</BaseModal> </BaseModal>
); );
}, },

View File

@ -1,7 +1,4 @@
import { import { ENABLE_INTEGRATIONS } from "@/customization/feature-flags";
ENABLE_INTEGRATIONS,
ENABLE_MVPS,
} from "@/customization/feature-flags";
import { useStoreStore } from "@/stores/storeStore"; import { useStoreStore } from "@/stores/storeStore";
import { cloneDeep } from "lodash"; import { cloneDeep } from "lodash";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";

View File

@ -1,4 +1,3 @@
import React from "react";
const NoResultsMessage = ({ const NoResultsMessage = ({
onClearSearch, onClearSearch,
message = "No components found.", message = "No components found.",

View File

@ -1,6 +1,5 @@
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import React from "react";
const FeatureToggles = ({ const FeatureToggles = ({
showBeta, showBeta,

View File

@ -2,7 +2,6 @@ import ForwardedIconComponent from "@/components/common/genericIconComponent";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { SidebarMenuButton } from "@/components/ui/sidebar"; import { SidebarMenuButton } from "@/components/ui/sidebar";
import { CustomLink } from "@/customization/components/custom-link"; import { CustomLink } from "@/customization/components/custom-link";
import React from "react";
const SidebarMenuButtons = ({ const SidebarMenuButtons = ({
hasStore = false, hasStore = false,

View File

@ -1,5 +1,4 @@
import { APIDataType } from "@/types/api"; import { APIDataType } from "@/types/api";
import { FuseResult } from "fuse.js";
export const filteredDataFn = ( export const filteredDataFn = (
data: APIDataType, data: APIDataType,

View File

@ -1,5 +1,4 @@
import { APIDataType } from "@/types/api"; import { APIDataType } from "@/types/api";
import { normalizeString } from "./normalize-string";
import { searchInMetadata } from "./search-on-metadata"; import { searchInMetadata } from "./search-on-metadata";
export const traditionalSearchMetadata = ( export const traditionalSearchMetadata = (

View File

@ -4,7 +4,7 @@ import EditNodeModal from "@/modals/editNodeModal";
import ShareModal from "@/modals/shareModal"; import ShareModal from "@/modals/shareModal";
import { APIClassType } from "@/types/api"; import { APIClassType } from "@/types/api";
import { FlowType } from "@/types/flow"; import { FlowType } from "@/types/flow";
import React, { memo } from "react"; import { memo } from "react";
interface ToolbarModalsProps { interface ToolbarModalsProps {
// Modal visibility states // Modal visibility states

View File

@ -1,6 +1,5 @@
import ForwardedIconComponent from "../../../../../components/common/genericIconComponent"; import ForwardedIconComponent from "../../../../../components/common/genericIconComponent";
import RenderIcons from "../../../../../components/common/renderIconComponent"; import RenderIcons from "../../../../../components/common/renderIconComponent";
import { IS_MAC } from "../../../../../constants/constants";
import { toolbarSelectItemProps } from "../../../../../types/components"; import { toolbarSelectItemProps } from "../../../../../types/components";
export default function ToolbarSelectItem({ export default function ToolbarSelectItem({

View File

@ -2,7 +2,7 @@ import { useGetFolderQuery } from "@/controllers/API/queries/folders/use-get-fol
import useDeleteFlow from "@/hooks/flows/use-delete-flow"; import useDeleteFlow from "@/hooks/flows/use-delete-flow";
import { useFolderStore } from "@/stores/foldersStore"; import { useFolderStore } from "@/stores/foldersStore";
import { useIsFetching, useIsMutating } from "@tanstack/react-query"; import { useIsFetching, useIsMutating } from "@tanstack/react-query";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useState } from "react";
import { useLocation, useParams } from "react-router-dom"; import { useLocation, useParams } from "react-router-dom";
import ComponentsComponent from "../componentsComponent"; import ComponentsComponent from "../componentsComponent";
import HeaderTabsSearchComponent from "./components/headerTabsSearchComponent"; import HeaderTabsSearchComponent from "./components/headerTabsSearchComponent";

View File

@ -10,7 +10,7 @@ import {
useGetApiKeysQuery, useGetApiKeysQuery,
} from "@/controllers/API/queries/api-keys"; } from "@/controllers/API/queries/api-keys";
import { SelectionChangedEvent } from "ag-grid-community"; import { SelectionChangedEvent } from "ag-grid-community";
import { useContext, useEffect, useRef, useState } from "react"; import { useContext, useEffect, useState } from "react";
import TableComponent from "../../../../components/core/parameterRenderComponent/components/tableComponent"; import TableComponent from "../../../../components/core/parameterRenderComponent/components/tableComponent";
import { AuthContext } from "../../../../contexts/authContext"; import { AuthContext } from "../../../../contexts/authContext";
import useAlertStore from "../../../../stores/alertStore"; import useAlertStore from "../../../../stores/alertStore";

View File

@ -1,6 +1,4 @@
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate"; import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
import { useTypesStore } from "@/stores/typesStore";
import { useEffect } from "react"; import { useEffect } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import useFlowsManagerStore from "../../stores/flowsManagerStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore";

View File

@ -1,5 +1,3 @@
import { FieldParserType, FieldValidatorType } from "../api";
export type getCodesObjProps = { export type getCodesObjProps = {
runCurlCode: string; runCurlCode: string;
webhookCurlCode: string; webhookCurlCode: string;

View File

@ -1,4 +1,3 @@
import { FlowType } from "@/types/flow";
import { FolderType } from "../../../pages/MainPage/entities"; import { FolderType } from "../../../pages/MainPage/entities";
export type FoldersStoreType = { export type FoldersStoreType = {

View File

@ -1,4 +1,3 @@
import { ColDef, ColGroupDef } from "ag-grid-community";
import { Message } from "../../messages"; import { Message } from "../../messages";
export type MessagesStoreType = { export type MessagesStoreType = {

View File

@ -316,6 +316,7 @@ import SvgWolfram from "../icons/Wolfram/Wolfram";
import { HackerNewsIcon } from "../icons/hackerNews"; import { HackerNewsIcon } from "../icons/hackerNews";
import { MistralIcon } from "../icons/mistral"; import { MistralIcon } from "../icons/mistral";
import { SupabaseIcon } from "../icons/supabase"; import { SupabaseIcon } from "../icons/supabase";
import { XAIIcon } from "../icons/xAI";
import { iconsType } from "../types/components"; import { iconsType } from "../types/components";
export const BG_NOISE = export const BG_NOISE =
"url(data:image/png;base64,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)"; "url(data:image/png;base64,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)";
@ -689,6 +690,7 @@ export const nodeIconsLucide: iconsType = {
OpenAI: OpenAiIcon, OpenAI: OpenAiIcon,
OpenRouter: OpenRouterIcon, OpenRouter: OpenRouterIcon,
DeepSeek: DeepSeekIcon, DeepSeek: DeepSeekIcon,
xAI: XAIIcon,
OpenAIEmbeddings: OpenAiIcon, OpenAIEmbeddings: OpenAiIcon,
Pinecone: PineconeIcon, Pinecone: PineconeIcon,
Qdrant: QDrantIcon, Qdrant: QDrantIcon,

View File

@ -2,7 +2,6 @@ import { expect, Page, test } from "@playwright/test";
import * as dotenv from "dotenv"; import * as dotenv from "dotenv";
import path from "path"; import path from "path";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test"; import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
import { evaluateReactStateChanges } from "../../utils/evaluate-input-react-state-changes";
import { initialGPTsetup } from "../../utils/initialGPTsetup"; import { initialGPTsetup } from "../../utils/initialGPTsetup";
test( test(

View File

@ -1,5 +1,4 @@
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import { adjustScreenView } from "../../utils/adjust-screen-view";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test"; import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
test( test(

View File

@ -25,6 +25,10 @@ test(
}, },
); );
await page.waitForSelector('[data-testid="zoom_out"]', {
timeout: 3000,
});
await page.getByTestId("sidebar-custom-component-button").click(); await page.getByTestId("sidebar-custom-component-button").click();
await page.getByTestId("zoom_out").click(); await page.getByTestId("zoom_out").click();
@ -164,7 +168,7 @@ class CustomComponent(Component):
numberOfCopiedRows = await page.getByText(thirdRandomText).count(); numberOfCopiedRows = await page.getByText(thirdRandomText).count();
expect(numberOfCopiedRows).toBe(0); expect(numberOfCopiedRows).toBe(0);
await page.getByText("Close").last().click(); await page.getByText("Save").last().click();
await page.waitForSelector("text=Open table", { await page.waitForSelector("text=Open table", {
timeout: 3000, timeout: 3000,

View File

@ -1,7 +1,5 @@
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import { readFileSync } from "fs";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test"; import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
import { simulateDragAndDrop } from "../../utils/simulate-drag-and-drop";
test( test(
"user should be able to edit flow name by clicking on the header or on the main page", "user should be able to edit flow name by clicking on the header or on the main page",
{ tag: ["@release"] }, { tag: ["@release"] },

View File

@ -1,4 +1,4 @@
import { expect, Page, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import { adjustScreenView } from "../../utils/adjust-screen-view"; import { adjustScreenView } from "../../utils/adjust-screen-view";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test"; import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";

View File

@ -1,4 +1,4 @@
import { expect, test } from "@playwright/test"; import { test } from "@playwright/test";
import * as dotenv from "dotenv"; import * as dotenv from "dotenv";
import path from "path"; import path from "path";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test"; import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";

View File

@ -1,4 +1,4 @@
import { expect, Page, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import * as dotenv from "dotenv"; import * as dotenv from "dotenv";
import path from "path"; import path from "path";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test"; import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";