Merge branch 'zustand/io/migration' of personal:logspace-ai/langflow into zustand/io/migration
This commit is contained in:
commit
cf4733e5a9
6 changed files with 99 additions and 26 deletions
|
|
@ -83,7 +83,8 @@ The CustomComponent class serves as the foundation for creating custom component
|
|||
| _`file_types: List[str]`_ | This is a requirement if the _`field_type`_ is _file_. Defines which file types will be accepted. For example, _json_, _yaml_ or _yml_. |
|
||||
| _`range_spec: langflow.field_typing.RangeSpec`_ | This is a requirement if the _`field_type`_ is _`float`_. Defines the range of values accepted and the step size. If none is defined, the default is _`[-1, 1, 0.1]`_. |
|
||||
| _`title_case: bool`_ | Formats the name of the field when _`display_name`_ is not defined. Set it to False to keep the name as you set it in the _`build`_ method. |
|
||||
| _`refresh: bool`_ | If set to True a button will appear to the right of the field, and when clicked, it will call the _`update_build_config`_ method which takes in the _`build_config`_, the name of the field (_`field_name`_) and the latest value of the field (_`field_value`_). This is useful when you want to update the _`build_config`_ based on the value of the field. |
|
||||
| _`refresh_button: bool`_ | If set to True a button will appear to the right of the field, and when clicked, it will call the _`update_build_config`_ method which takes in the _`build_config`_, the name of the field (_`field_name`_) and the latest value of the field (_`field_value`_). This is useful when you want to update the _`build_config`_ based on the value of the field. |
|
||||
| _`real_time_refresh: bool`_ | If set to True, the _`update_build_config`_ method will be called every time the field value changes. |
|
||||
|
||||
<Admonition type="info" label="Tip">
|
||||
|
||||
|
|
|
|||
|
|
@ -468,7 +468,9 @@ def update_field_dict(
|
|||
call: bool = False,
|
||||
):
|
||||
"""Update the field dictionary by calling options() or value() if they are callable"""
|
||||
if "refresh" in field_dict:
|
||||
if ("real_time_refresh" in field_dict or "refresh_button" in field_dict) and any(
|
||||
(field_dict["real_time_refresh"], field_dict["refresh_button"])
|
||||
):
|
||||
if call:
|
||||
try:
|
||||
dd_build_config = dotdict(build_config)
|
||||
|
|
@ -481,7 +483,6 @@ def update_field_dict(
|
|||
raise UpdateBuildConfigError(
|
||||
f"Error while running update_build_config: {str(exc)}"
|
||||
) from exc
|
||||
field_dict["refresh"] = True
|
||||
|
||||
# Let's check if "range_spec" is a RangeSpec object
|
||||
if "rangeSpec" in field_dict and isinstance(field_dict["rangeSpec"], RangeSpec):
|
||||
|
|
|
|||
|
|
@ -65,10 +65,17 @@ class TemplateField(BaseModel):
|
|||
info: Optional[str] = ""
|
||||
"""Additional information about the field to be shown in the tooltip. Defaults to an empty string."""
|
||||
|
||||
refresh: Optional[bool] = None
|
||||
"""Specifies if the field should be refreshed. Defaults to False."""
|
||||
real_time_refresh: Optional[bool] = None
|
||||
"""Specifies if the field should have real time refresh. `refresh_button` must be False. Defaults to None."""
|
||||
|
||||
range_spec: Optional[RangeSpec] = Field(default=None, serialization_alias="rangeSpec")
|
||||
refresh_button: Optional[bool] = None
|
||||
"""Specifies if the field should have a refresh button. Defaults to False."""
|
||||
refresh_button_text: Optional[str] = None
|
||||
"""Specifies the text for the refresh button. Defaults to None."""
|
||||
|
||||
range_spec: Optional[RangeSpec] = Field(
|
||||
default=None, serialization_alias="rangeSpec"
|
||||
)
|
||||
"""Range specification for the field. Defaults to None."""
|
||||
|
||||
title_case: bool = False
|
||||
|
|
@ -117,6 +124,10 @@ class TemplateField(BaseModel):
|
|||
if not isinstance(value, list):
|
||||
raise ValueError("file_types must be a list")
|
||||
return [
|
||||
(f".{file_type}" if isinstance(file_type, str) and not file_type.startswith(".") else file_type)
|
||||
(
|
||||
f".{file_type}"
|
||||
if isinstance(file_type, str) and not file_type.startswith(".")
|
||||
else file_type
|
||||
)
|
||||
for file_type in value
|
||||
]
|
||||
|
|
|
|||
|
|
@ -88,10 +88,36 @@ export default function ParameterComponent({
|
|||
|
||||
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
|
||||
|
||||
const handleRefreshButtonPress = async (name, data) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
let newTemplate = await handleUpdateValues(name, data);
|
||||
if (newTemplate) {
|
||||
setNode(data.id, (oldNode) => {
|
||||
let newNode = cloneDeep(oldNode);
|
||||
newNode.data = {
|
||||
...newNode.data,
|
||||
};
|
||||
newNode.data.node.template = newTemplate;
|
||||
return newNode;
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
let responseError = error as ResponseErrorTypeAPI;
|
||||
setErrorData({
|
||||
title: "Error while updating the Component",
|
||||
list: [responseError.response.data.detail.error ?? "Unknown error"],
|
||||
});
|
||||
}
|
||||
setIsLoading(false);
|
||||
renderTooltips();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
if (
|
||||
data.node?.template[name]?.refresh &&
|
||||
(data.node?.template[name]?.real_time_refresh ||
|
||||
data.node?.template[name]?.refresh_button) &&
|
||||
// options can be undefined but not an empty array
|
||||
(data.node?.template[name]?.options?.length ?? 0) === 0
|
||||
) {
|
||||
|
|
@ -128,7 +154,8 @@ export default function ParameterComponent({
|
|||
takeSnapshot();
|
||||
}
|
||||
const shouldUpdate =
|
||||
data.node?.template[name].refresh &&
|
||||
data.node?.template[name].real_time_refresh &&
|
||||
!data.node?.template[name].refresh_button &&
|
||||
data.node!.template[name].value !== newValue;
|
||||
|
||||
data.node!.template[name].value = newValue; // necessary to enable ctrl+z inside the input
|
||||
|
|
@ -154,7 +181,7 @@ export default function ParameterComponent({
|
|||
...newNode.data,
|
||||
};
|
||||
|
||||
if (data.node?.template[name].refresh && newTemplate) {
|
||||
if (data.node?.template[name].real_time_refresh && newTemplate) {
|
||||
newNode.data.node.template = newTemplate;
|
||||
} else newNode.data.node.template[name].value = newValue;
|
||||
|
||||
|
|
@ -458,7 +485,7 @@ export default function ParameterComponent({
|
|||
}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
{/* {data.node?.template[name].refresh && (
|
||||
{/* {data.node?.template[name].refresh_button && (
|
||||
<div className="w-1/6">
|
||||
<RefreshButton
|
||||
isLoading={isLoading}
|
||||
|
|
@ -466,26 +493,47 @@ export default function ParameterComponent({
|
|||
name={name}
|
||||
data={data}
|
||||
className="extra-side-bar-buttons ml-2 mt-1"
|
||||
handleUpdateValues={handleUpdateValues}
|
||||
handleUpdateValues={handleRefreshButtonPress}
|
||||
id={"refresh-button-" + name}
|
||||
/>
|
||||
</div>
|
||||
)} */}
|
||||
</div>
|
||||
) : data.node?.template[name].multiline ? (
|
||||
<TextAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={handleOnNewValue}
|
||||
id={"textarea-" + data.node.template[name].name}
|
||||
data-testid={"textarea-" + data.node.template[name].name}
|
||||
/>
|
||||
<div className="mt-2 flex w-full flex-col ">
|
||||
<div className="flex-grow">
|
||||
<TextAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={handleOnNewValue}
|
||||
id={"textarea-" + data.node.template[name].name}
|
||||
data-testid={"textarea-" + data.node.template[name].name}
|
||||
/>
|
||||
</div>
|
||||
{data.node?.template[name].refresh_button && (
|
||||
<div className="flex-grow">
|
||||
<RefreshButton
|
||||
isLoading={isLoading}
|
||||
disabled={disabled}
|
||||
name={name}
|
||||
data={data}
|
||||
button_text={
|
||||
data.node?.template[name].refresh_button_text ??
|
||||
"Refresh"
|
||||
}
|
||||
className="extra-side-bar-buttons mt-1"
|
||||
handleUpdateValues={handleRefreshButtonPress}
|
||||
id={"refresh-button-" + name}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-2 flex w-full items-center">
|
||||
<div
|
||||
className={
|
||||
"flex-grow " +
|
||||
(data.node?.template[name].refresh ? "w-5/6" : "")
|
||||
(data.node?.template[name].refresh_button ? "w-5/6" : "")
|
||||
}
|
||||
>
|
||||
<InputComponent
|
||||
|
|
@ -496,15 +544,19 @@ export default function ParameterComponent({
|
|||
onChange={handleOnNewValue}
|
||||
/>
|
||||
</div>
|
||||
{data.node?.template[name].refresh && (
|
||||
{data.node?.template[name].refresh_button && (
|
||||
<div className="w-1/6">
|
||||
<RefreshButton
|
||||
isLoading={isLoading}
|
||||
disabled={disabled}
|
||||
name={name}
|
||||
data={data}
|
||||
button_text={
|
||||
data.node?.template[name].refresh_button_text ??
|
||||
"Refresh"
|
||||
}
|
||||
className="extra-side-bar-buttons ml-2 mt-1"
|
||||
handleUpdateValues={handleUpdateValues}
|
||||
handleUpdateValues={handleRefreshButtonPress}
|
||||
id={"refresh-button-" + name}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -535,7 +587,7 @@ export default function ParameterComponent({
|
|||
) : left === true &&
|
||||
type === "str" &&
|
||||
(data.node?.template[name].options ||
|
||||
data.node?.template[name]?.refresh) ? (
|
||||
data.node?.template[name]?.real_time_refresh) ? (
|
||||
// TODO: Improve CSS
|
||||
<div className="mt-2 flex w-full items-center">
|
||||
<div className="w-5/6 flex-grow">
|
||||
|
|
@ -548,15 +600,18 @@ export default function ParameterComponent({
|
|||
id={"dropdown-" + name}
|
||||
/>
|
||||
</div>
|
||||
{data.node?.template[name].refresh && (
|
||||
{data.node?.template[name].refresh_button && (
|
||||
<div className="w-1/6">
|
||||
<RefreshButton
|
||||
isLoading={isLoading}
|
||||
disabled={disabled}
|
||||
name={name}
|
||||
data={data}
|
||||
button_text={
|
||||
data.node?.template[name].refresh_button_text ?? "Refresh"
|
||||
}
|
||||
className="extra-side-bar-buttons ml-2 mt-1"
|
||||
handleUpdateValues={handleUpdateValues}
|
||||
handleUpdateValues={handleRefreshButtonPress}
|
||||
id={"refresh-button-" + name}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ function RefreshButton({
|
|||
isLoading,
|
||||
disabled,
|
||||
name,
|
||||
button_text,
|
||||
data,
|
||||
handleUpdateValues,
|
||||
className,
|
||||
|
|
@ -15,6 +16,7 @@ function RefreshButton({
|
|||
isLoading: boolean;
|
||||
disabled: boolean;
|
||||
name: string;
|
||||
button_text: string;
|
||||
data: NodeDataType;
|
||||
className?: string;
|
||||
handleUpdateValues: (name: string, data: NodeDataType) => void;
|
||||
|
|
@ -43,6 +45,7 @@ function RefreshButton({
|
|||
onClick={handleClick}
|
||||
id={id}
|
||||
>
|
||||
<span className="mr-1">{button_text}</span>
|
||||
<IconComponent
|
||||
name={isLoading ? "Loader2" : "RefreshCcw"}
|
||||
className={iconClassName}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@ export type TemplateVariableType = {
|
|||
input_types?: Array<string>;
|
||||
display_name?: string;
|
||||
name?: string;
|
||||
refresh?: boolean;
|
||||
real_time_refresh?: boolean;
|
||||
refresh_button?: boolean;
|
||||
refresh_button_text?: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
export type sendAllProps = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue