Merge branch 'dev' into 335-implement-docarray-vectorstore
This commit is contained in:
commit
12c23408e0
16 changed files with 138 additions and 223 deletions
|
|
@ -18,59 +18,10 @@ def get_number_of_workers(workers=None):
|
|||
return workers
|
||||
|
||||
|
||||
def update_settings(config: str):
|
||||
def update_settings(config: str, dev: bool = False):
|
||||
"""Update the settings from a config file."""
|
||||
if config:
|
||||
settings.update_from_yaml(config)
|
||||
|
||||
|
||||
@app.command()
|
||||
def serve(
|
||||
host: str = typer.Option("127.0.0.1", help="Host to bind the server to."),
|
||||
workers: int = typer.Option(1, help="Number of worker processes."),
|
||||
timeout: int = typer.Option(60, help="Worker timeout in seconds."),
|
||||
port: int = typer.Option(7860, help="Port to listen on."),
|
||||
config: str = typer.Option("config.yaml", help="Path to the configuration file."),
|
||||
log_level: str = typer.Option("info", help="Logging level."),
|
||||
log_file: Path = typer.Option("logs/langflow.log", help="Path to the log file."),
|
||||
jcloud: bool = typer.Option(False, help="Deploy on Jina AI Cloud"),
|
||||
):
|
||||
"""
|
||||
Run the Langflow server.
|
||||
"""
|
||||
|
||||
if jcloud:
|
||||
return serve_on_jcloud()
|
||||
|
||||
configure(log_level=log_level, log_file=log_file)
|
||||
update_settings(config)
|
||||
app = create_app()
|
||||
# get the directory of the current file
|
||||
path = Path(__file__).parent
|
||||
static_files_dir = path / "frontend"
|
||||
app.mount(
|
||||
"/",
|
||||
StaticFiles(directory=static_files_dir, html=True),
|
||||
name="static",
|
||||
)
|
||||
options = {
|
||||
"bind": f"{host}:{port}",
|
||||
"workers": get_number_of_workers(workers),
|
||||
"worker_class": "uvicorn.workers.UvicornWorker",
|
||||
"timeout": timeout,
|
||||
}
|
||||
|
||||
if platform.system() in ["Darwin", "Windows"]:
|
||||
# Run using uvicorn on MacOS and Windows
|
||||
# Windows doesn't support gunicorn
|
||||
# MacOS requires an env variable to be set to use gunicorn
|
||||
import uvicorn
|
||||
|
||||
uvicorn.run(app, host=host, port=port, log_level=log_level)
|
||||
else:
|
||||
from langflow.server import LangflowApplication
|
||||
|
||||
LangflowApplication(app, options).run()
|
||||
settings.update_from_yaml(config, dev=dev)
|
||||
|
||||
|
||||
def serve_on_jcloud():
|
||||
|
|
@ -119,6 +70,56 @@ def serve_on_jcloud():
|
|||
click.secho("https://github.com/jina-ai/langchain-serve", fg="blue")
|
||||
|
||||
|
||||
@app.command()
|
||||
def serve(
|
||||
host: str = typer.Option("127.0.0.1", help="Host to bind the server to."),
|
||||
workers: int = typer.Option(1, help="Number of worker processes."),
|
||||
timeout: int = typer.Option(60, help="Worker timeout in seconds."),
|
||||
port: int = typer.Option(7860, help="Port to listen on."),
|
||||
config: str = typer.Option("config.yaml", help="Path to the configuration file."),
|
||||
log_level: str = typer.Option("info", help="Logging level."),
|
||||
log_file: Path = typer.Option("logs/langflow.log", help="Path to the log file."),
|
||||
jcloud: bool = typer.Option(False, help="Deploy on Jina AI Cloud"),
|
||||
dev: bool = typer.Option(False, help="Run in development mode (may contain bugs)"),
|
||||
):
|
||||
"""
|
||||
Run the Langflow server.
|
||||
"""
|
||||
|
||||
if jcloud:
|
||||
return serve_on_jcloud()
|
||||
|
||||
configure(log_level=log_level, log_file=log_file)
|
||||
update_settings(config, dev=dev)
|
||||
app = create_app()
|
||||
# get the directory of the current file
|
||||
path = Path(__file__).parent
|
||||
static_files_dir = path / "frontend"
|
||||
app.mount(
|
||||
"/",
|
||||
StaticFiles(directory=static_files_dir, html=True),
|
||||
name="static",
|
||||
)
|
||||
options = {
|
||||
"bind": f"{host}:{port}",
|
||||
"workers": get_number_of_workers(workers),
|
||||
"worker_class": "uvicorn.workers.UvicornWorker",
|
||||
"timeout": timeout,
|
||||
}
|
||||
|
||||
if platform.system() in ["Darwin", "Windows"]:
|
||||
# Run using uvicorn on MacOS and Windows
|
||||
# Windows doesn't support gunicorn
|
||||
# MacOS requires an env variable to be set to use gunicorn
|
||||
import uvicorn
|
||||
|
||||
uvicorn.run(app, host=host, port=port, log_level=log_level)
|
||||
else:
|
||||
from langflow.server import LangflowApplication
|
||||
|
||||
LangflowApplication(app, options).run()
|
||||
|
||||
|
||||
def main():
|
||||
app()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ chains:
|
|||
- MidJourneyPromptChain
|
||||
- TimeTravelGuideChain
|
||||
- SQLDatabaseChain
|
||||
dev: false
|
||||
documentloaders:
|
||||
- AirbyteJSONLoader
|
||||
- CoNLLULoader
|
||||
|
|
@ -109,9 +108,6 @@ utilities:
|
|||
- SQLDatabase
|
||||
vectorstores:
|
||||
- Chroma
|
||||
- DocArrayHnswSearch
|
||||
- DocArrayInMemorySearch
|
||||
- Qdrant
|
||||
wrappers:
|
||||
- RequestsWrapper # Wait more tests
|
||||
# - ChatPromptTemplate
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class Settings(BaseSettings):
|
|||
values[key] = []
|
||||
return values
|
||||
|
||||
def update_from_yaml(self, file_path: str):
|
||||
def update_from_yaml(self, file_path: str, dev: bool = False):
|
||||
new_settings = load_settings_from_yaml(file_path)
|
||||
self.chains = new_settings.chains or []
|
||||
self.agents = new_settings.agents or []
|
||||
|
|
@ -44,7 +44,7 @@ class Settings(BaseSettings):
|
|||
self.toolkits = new_settings.toolkits or []
|
||||
self.textsplitters = new_settings.textsplitters or []
|
||||
self.utilities = new_settings.utilities or []
|
||||
self.dev = new_settings.dev or False
|
||||
self.dev = dev
|
||||
|
||||
|
||||
def save_settings_to_yaml(settings: Settings, file_path: str):
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ export default function FloatComponent({
|
|||
onChange("");
|
||||
}
|
||||
}, [disabled, onChange]);
|
||||
const {setDisableCopyPaste} = useContext(TabsContext)
|
||||
return (
|
||||
<div className={disabled ? "pointer-events-none cursor-not-allowed" : ""}>
|
||||
<input
|
||||
|
|
@ -29,12 +28,7 @@ export default function FloatComponent({
|
|||
setMyValue(e.target.value);
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
onBlur={() => {
|
||||
setDisableCopyPaste(false)
|
||||
}}
|
||||
onFocus={() => {
|
||||
setDisableCopyPaste(true)
|
||||
}}
|
||||
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ export default function InputComponent({
|
|||
}: InputComponentType) {
|
||||
const [myValue, setMyValue] = useState(value ?? "");
|
||||
const [pwdVisible, setPwdVisible] = useState(false);
|
||||
const {setDisableCopyPaste} = useContext(TabsContext)
|
||||
useEffect(() => {
|
||||
if (disabled) {
|
||||
setMyValue("");
|
||||
|
|
@ -28,12 +27,7 @@ export default function InputComponent({
|
|||
>
|
||||
<input
|
||||
value={myValue}
|
||||
onBlur={() => {
|
||||
setDisableCopyPaste(false)
|
||||
}}
|
||||
onFocus={() => {
|
||||
setDisableCopyPaste(true)
|
||||
}}
|
||||
|
||||
className={classNames(
|
||||
"block w-full pr-12 form-input dark:bg-gray-900 dark:border-gray-600 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm",
|
||||
disabled ? " bg-gray-200 dark:bg-gray-700" : "",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ export default function InputListComponent({
|
|||
onChange([""]);
|
||||
}
|
||||
}, [disabled, onChange]);
|
||||
const {setDisableCopyPaste} = useContext(TabsContext)
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
|
|
@ -43,12 +42,6 @@ export default function InputListComponent({
|
|||
});
|
||||
onChange(inputList);
|
||||
}}
|
||||
onBlur={() => {
|
||||
setDisableCopyPaste(false)
|
||||
}}
|
||||
onFocus={() => {
|
||||
setDisableCopyPaste(true)
|
||||
}}
|
||||
/>
|
||||
{idx === inputList.length - 1 ? (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ export default function IntComponent({
|
|||
onChange("");
|
||||
}
|
||||
}, [disabled, onChange]);
|
||||
const {setDisableCopyPaste} =useContext(TabsContext)
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
|
|
@ -45,12 +44,7 @@ export default function IntComponent({
|
|||
setMyValue(e.target.value);
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
onBlur={() => {
|
||||
setDisableCopyPaste(false)
|
||||
}}
|
||||
onFocus={() => {
|
||||
setDisableCopyPaste(true)
|
||||
}}
|
||||
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ export default function ChatInput({
|
|||
}
|
||||
}, [chatValue]);
|
||||
|
||||
const { setDisableCopyPaste } = useContext(TabsContext);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<textarea
|
||||
|
|
@ -27,12 +25,6 @@ export default function ChatInput({
|
|||
sendMessage();
|
||||
}
|
||||
}}
|
||||
onBlur={() => {
|
||||
setDisableCopyPaste(false)
|
||||
}}
|
||||
onFocus={() => {
|
||||
setDisableCopyPaste(true)
|
||||
}}
|
||||
rows={1}
|
||||
ref={inputRef}
|
||||
disabled={lockChat}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { sendAllProps } from "../../types/api";
|
|||
import { ChatMessageType, ChatType } from "../../types/chat";
|
||||
import ChatInput from "./chatInput";
|
||||
|
||||
import _ from "lodash";
|
||||
import _, { set } from "lodash";
|
||||
|
||||
export default function ChatModal({
|
||||
flow,
|
||||
|
|
@ -100,9 +100,9 @@ export default function ChatModal({
|
|||
function handleOnClose(event: CloseEvent) {
|
||||
if (isOpen.current) {
|
||||
setErrorData({ title: event.reason });
|
||||
setLockChat(false);
|
||||
setTimeout(() => {
|
||||
connectWS();
|
||||
setLockChat(false);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
|
@ -235,6 +235,13 @@ export default function ChatModal({
|
|||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if((ws.current.readyState=== ws.current.CLOSED || ws.current.readyState=== ws.current.CLOSING)){
|
||||
connectWS();
|
||||
setLockChat(false);
|
||||
}
|
||||
},[lockChat]);
|
||||
|
||||
async function sendAll(data: sendAllProps) {
|
||||
try {
|
||||
if (ws) {
|
||||
|
|
@ -339,6 +346,7 @@ export default function ChatModal({
|
|||
function clearChat() {
|
||||
setChatHistory([]);
|
||||
ws.current.send(JSON.stringify({ clear_history: true }));
|
||||
if(lockChat) setLockChat(false);
|
||||
}
|
||||
|
||||
function setModalOpen(x: boolean) {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ export default function CodeAreaModal({
|
|||
const [code, setCode] = useState(value);
|
||||
const { dark } = useContext(darkContext);
|
||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||
const { setDisableCopyPaste } = useContext(TabsContext);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
const ref = useRef();
|
||||
function setModalOpen(x: boolean) {
|
||||
|
|
@ -111,12 +110,6 @@ export default function CodeAreaModal({
|
|||
onChange={(value) => {
|
||||
setCode(value);
|
||||
}}
|
||||
onBlur={() => {
|
||||
setDisableCopyPaste(false)
|
||||
}}
|
||||
onFocus={() => {
|
||||
setDisableCopyPaste(true)
|
||||
}}
|
||||
className="h-full w-full rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export default function ExportModal() {
|
|||
const { closePopUp } = useContext(PopUpContext);
|
||||
const ref = useRef();
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
const { flows, tabIndex, updateFlow, downloadFlow,setDisableCopyPaste } = useContext(TabsContext);
|
||||
const { flows, tabIndex, updateFlow, downloadFlow } = useContext(TabsContext);
|
||||
function setModalOpen(x: boolean) {
|
||||
setOpen(x);
|
||||
if (x === false) {
|
||||
|
|
@ -113,12 +113,6 @@ export default function ExportModal() {
|
|||
placeholder="File name"
|
||||
id="name"
|
||||
className="focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500 text-gray-900 dark:text-gray-100"
|
||||
onBlur={() => {
|
||||
setDisableCopyPaste(false);
|
||||
}}
|
||||
onFocus={() => {
|
||||
setDisableCopyPaste(true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
|
|
@ -133,12 +127,6 @@ export default function ExportModal() {
|
|||
</span>
|
||||
</label>
|
||||
<textarea
|
||||
onBlur={() => {
|
||||
setDisableCopyPaste(false);
|
||||
}}
|
||||
onFocus={() => {
|
||||
setDisableCopyPaste(true);
|
||||
}}
|
||||
name="description"
|
||||
id="description"
|
||||
onChange={(event) => {
|
||||
|
|
@ -163,12 +151,7 @@ export default function ExportModal() {
|
|||
id="checkbox"
|
||||
type="checkbox"
|
||||
className="h-4 w-4 text-blue-600 border-gray-300 rounded dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500"
|
||||
onBlur={() => {
|
||||
setDisableCopyPaste(false);
|
||||
}}
|
||||
onFocus={() => {
|
||||
setDisableCopyPaste(true);
|
||||
}}
|
||||
|
||||
/>
|
||||
<span className="ml-2 font-medium text-gray-700 dark:text-white">
|
||||
Save with my API keys
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export default function ButtonBox({
|
|||
}) {
|
||||
let bigCircle: string;
|
||||
let smallCircle: string;
|
||||
let minTitleFontSize: number;
|
||||
let titleFontSize: string;
|
||||
let descriptionFontSize: string;
|
||||
let padding: string;
|
||||
let marginTop: string;
|
||||
|
|
@ -32,88 +32,48 @@ export default function ButtonBox({
|
|||
let width: string;
|
||||
let textHeight: number;
|
||||
let textWidth: number;
|
||||
const [truncate, setTruncate] = useState<boolean>(false);
|
||||
switch (size) {
|
||||
case "small":
|
||||
bigCircle = "h-12 w-12";
|
||||
smallCircle = "h-8 w-8";
|
||||
minTitleFontSize =9;
|
||||
descriptionFontSize = "text-xs";
|
||||
padding = "p-2 py-3";
|
||||
marginTop = "mt-2";
|
||||
height = "h-36";
|
||||
textHeight = 70;
|
||||
textWidth = 40;
|
||||
width = "w-32";
|
||||
break;
|
||||
case "medium":
|
||||
bigCircle = "h-16 w-16";
|
||||
smallCircle = "h-12 w-12";
|
||||
minTitleFontSize = 11;
|
||||
descriptionFontSize = "text-sm";
|
||||
padding = "p-4 py-5";
|
||||
marginTop = "mt-3";
|
||||
textHeight = 112;
|
||||
textWidth = 162;
|
||||
height = "h-44";
|
||||
width = "w-36";
|
||||
break;
|
||||
case "big":
|
||||
bigCircle = "h-20 w-20";
|
||||
smallCircle = "h-16 w-16";
|
||||
minTitleFontSize = 12;
|
||||
descriptionFontSize = "text-sm";
|
||||
padding = "p-8 py-10";
|
||||
marginTop = "mt-6";
|
||||
height = "h-56";
|
||||
width = "w-44";
|
||||
break;
|
||||
default:
|
||||
bigCircle = "h-20 w-20";
|
||||
smallCircle = "h-16 w-16";
|
||||
minTitleFontSize = 12;
|
||||
descriptionFontSize = "text-sm";
|
||||
padding = "p-8 py-10";
|
||||
marginTop = "mt-6";
|
||||
height = "h-56";
|
||||
width = "w-44";
|
||||
break;
|
||||
}
|
||||
|
||||
const [fontSize, setFontSize] = useState<number>(16); // Initial font size value
|
||||
|
||||
const titleRef = useRef<HTMLHeadingElement>(null);
|
||||
const parentDivRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const textElement = titleRef.current;
|
||||
const parentDivElement = parentDivRef.current;
|
||||
|
||||
if (!textElement || !parentDivElement) return;
|
||||
|
||||
const parentDivHeight = parentDivElement.offsetHeight;
|
||||
const parentDivWidth = parentDivElement.offsetWidth;
|
||||
let textElementHeight = textElement.scrollHeight;
|
||||
let textElementWidth = textElement.scrollWidth;
|
||||
|
||||
if (textElementHeight > parentDivHeight || textElementWidth > parentDivWidth && fontSize > minTitleFontSize) {
|
||||
let newFontSize = fontSize;
|
||||
|
||||
while (textElementHeight > parentDivHeight || textElementWidth > parentDivWidth) {
|
||||
newFontSize -= 1;
|
||||
textElement.style.fontSize = `${newFontSize}px`;
|
||||
textElementHeight = textElement.scrollHeight;
|
||||
textElementWidth = textElement.scrollWidth;
|
||||
}
|
||||
if(newFontSize <= minTitleFontSize){
|
||||
setTruncate(true);
|
||||
setFontSize(minTitleFontSize);
|
||||
}
|
||||
else{
|
||||
setFontSize(newFontSize);
|
||||
}
|
||||
case "small":
|
||||
bigCircle = "h-12 w-12";
|
||||
smallCircle = "h-8 w-8";
|
||||
titleFontSize = "text-sm";
|
||||
descriptionFontSize = "text-xs";
|
||||
padding = "p-2 py-3";
|
||||
marginTop = "mt-2";
|
||||
height = "h-36";
|
||||
width = "w-32";
|
||||
break;
|
||||
case "medium":
|
||||
bigCircle = "h-16 w-16";
|
||||
smallCircle = "h-12 w-12";
|
||||
titleFontSize = "text-base";
|
||||
descriptionFontSize = "text-sm";
|
||||
padding = "p-4 py-5";
|
||||
marginTop = "mt-3";
|
||||
height = "h-44";
|
||||
width = "w-36";
|
||||
break;
|
||||
case "big":
|
||||
bigCircle = "h-20 w-20";
|
||||
smallCircle = "h-16 w-16";
|
||||
titleFontSize = "text-lg";
|
||||
descriptionFontSize = "text-sm";
|
||||
padding = "p-8 py-10";
|
||||
marginTop = "mt-6";
|
||||
height = "h-56";
|
||||
width = "w-44";
|
||||
break;
|
||||
default:
|
||||
bigCircle = "h-20 w-20";
|
||||
smallCircle = "h-16 w-16";
|
||||
titleFontSize = "text-lg";
|
||||
descriptionFontSize = "text-sm";
|
||||
padding = "p-8 py-10";
|
||||
marginTop = "mt-6";
|
||||
height = "h-56";
|
||||
width = "w-44";
|
||||
break;
|
||||
}
|
||||
}, [title, size, fontSize]);
|
||||
|
||||
|
||||
return (
|
||||
|
|
@ -136,15 +96,17 @@ export default function ButtonBox({
|
|||
<div className={textColor}>{icon}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ref={parentDivRef} className="w-full h-1/2 mt-auto">
|
||||
<div
|
||||
ref={titleRef}
|
||||
className={classNames(truncate?"truncate":"",
|
||||
" font-semibold text-white h-full dark:text-white/80",
|
||||
)} >
|
||||
{title}
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full mt-auto mb-auto">
|
||||
<h3
|
||||
className={classNames(
|
||||
"w-full font-semibold break-words text-white dark:text-white/80 truncate-multiline",
|
||||
titleFontSize,
|
||||
marginTop
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -177,10 +177,10 @@ export default function ImportModal() {
|
|||
!loadingExamples &&
|
||||
examples.map((example, index) => {
|
||||
return (
|
||||
<div id="index">
|
||||
<div key={index}>
|
||||
{" "}
|
||||
<ButtonBox
|
||||
size="big"
|
||||
size="small"
|
||||
bgColor="bg-emerald-500 dark:bg-emerald-500/75"
|
||||
description={
|
||||
example.description ?? "Prebuilt Examples"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export default function TabComponent({
|
|||
selected: boolean;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
const { removeFlow, updateFlow, flows, setDisableCopyPaste } = useContext(TabsContext);
|
||||
const { removeFlow, updateFlow, flows } = useContext(TabsContext);
|
||||
const [isRename, setIsRename] = useState(false);
|
||||
const [value, setValue] = useState("");
|
||||
return (
|
||||
|
|
@ -40,14 +40,10 @@ export default function TabComponent({
|
|||
<div className="bg-white dark:text-white dark:bg-gray-700/60 flex select-none justify-between w-44 items-center border border-b-0 border-gray-300 dark:border-gray-600 px-4 py-1 rounded-t-xl -ml-px">
|
||||
{isRename ? (
|
||||
<input
|
||||
onFocus={() => {
|
||||
setDisableCopyPaste(true);
|
||||
}}
|
||||
autoFocus
|
||||
className="bg-transparent focus:border-none active:outline hover:outline focus:outline outline-gray-300 rounded-md w-28"
|
||||
onBlur={() => {
|
||||
setIsRename(false);
|
||||
setDisableCopyPaste(false);
|
||||
if (value !== "") {
|
||||
let newFlow = _.cloneDeep(flow);
|
||||
newFlow.name = value;
|
||||
|
|
|
|||
|
|
@ -155,10 +155,6 @@ export default function FlowPage({ flow }: { flow: FlowType }) {
|
|||
params.targetHandle.split("|")[0] === "Text"
|
||||
? { stroke: "#333333", strokeWidth: 2 }
|
||||
: { stroke: "#222222" },
|
||||
className:
|
||||
params.targetHandle.split("|")[0] === "Text"
|
||||
? ""
|
||||
: "animate-pulse",
|
||||
animated: params.targetHandle.split("|")[0] === "Text",
|
||||
},
|
||||
eds
|
||||
|
|
@ -306,8 +302,10 @@ export default function FlowPage({ flow }: { flow: FlowType }) {
|
|||
setLastSelection(flow);
|
||||
}, []);
|
||||
|
||||
const {setDisableCopyPaste} = useContext(TabsContext)
|
||||
|
||||
return (
|
||||
<div className="w-full h-full" ref={reactFlowWrapper}>
|
||||
<div className="w-full h-full" ref={reactFlowWrapper} >
|
||||
{Object.keys(templates).length > 0 && Object.keys(types).length > 0 ? (
|
||||
<>
|
||||
<ReactFlow
|
||||
|
|
@ -316,6 +314,9 @@ export default function FlowPage({ flow }: { flow: FlowType }) {
|
|||
updateFlow({ ...flow, data: reactFlowInstance.toObject() });
|
||||
}}
|
||||
edges={edges}
|
||||
onPaneClick={() => {setDisableCopyPaste(false);}}
|
||||
onNodeClick={() => {setDisableCopyPaste(true);}}
|
||||
onPaneMouseLeave={() => {setDisableCopyPaste(true);}}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChangeMod}
|
||||
onConnect={onConnect}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,14 @@ module.exports = {
|
|||
display: "none",
|
||||
},
|
||||
},
|
||||
".truncate-multiline": {
|
||||
"display": "-webkit-box",
|
||||
"-webkit-line-clamp": "3", /* Change this number to the number of lines you want to show */
|
||||
"-webkit-box-orient": "vertical",
|
||||
"overflow": "hidden",
|
||||
"text-overflow": "ellipsis",
|
||||
},
|
||||
|
||||
".arrow-hide": {
|
||||
"&::-webkit-inner-spin-button": {
|
||||
"-webkit-appearance": "none",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue