chore: Update function calling add menu (#40139)
## Description Update the add menu responsibilites <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced an enhanced menu for adding function calls with options to create new queries or JavaScript objects and a curated list of available items. - **Refactor** - Updated the interface for function call configuration by streamlining legacy options, resulting in a more consistent and responsive user experience. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
df34a10205
commit
326023d0ab
|
|
@ -1,10 +1,34 @@
|
|||
import { Button, Text } from "@appsmith/ads";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
Icon,
|
||||
Menu,
|
||||
MenuContent,
|
||||
MenuGroup,
|
||||
MenuItem,
|
||||
MenuSub,
|
||||
MenuSubContent,
|
||||
MenuSubTrigger,
|
||||
MenuTrigger,
|
||||
Text,
|
||||
} from "@appsmith/ads";
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import type { FieldArrayFieldsProps } from "redux-form";
|
||||
import styled from "styled-components";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import type { FunctionCallingConfigFormToolField } from "../types";
|
||||
import type {
|
||||
FunctionCallingConfigFormToolField,
|
||||
FunctionCallingEntityType,
|
||||
FunctionCallingEntityTypeOption,
|
||||
} from "../types";
|
||||
import { FunctionCallingConfigToolField } from "./FunctionCallingConfigToolField";
|
||||
import { useSelector } from "react-redux";
|
||||
import { selectEntityOptions } from "./selectors";
|
||||
import { createNewJSCollection } from "actions/jsPaneActions";
|
||||
import { queryAddURL } from "ee/RouteBuilder";
|
||||
import history from "utils/history";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { getCurrentPageId } from "selectors/editorSelectors";
|
||||
|
||||
export interface FunctionCallingConfigFormProps {
|
||||
formName: string;
|
||||
|
|
@ -29,19 +53,48 @@ export const FunctionCallingConfigForm = ({
|
|||
formName,
|
||||
}: FunctionCallingConfigFormProps) => {
|
||||
const [newlyAddedId, setNewlyAddedId] = useState<string | null>(null);
|
||||
const options = useSelector(selectEntityOptions);
|
||||
const dispatch = useDispatch();
|
||||
const pageId = useSelector(getCurrentPageId);
|
||||
|
||||
const handleAddFunctionButtonClick = useCallback(() => {
|
||||
const id = uuid();
|
||||
// Get existing entity IDs from the agentFunctions, excluding the currently selected value
|
||||
const existingEntityIds = useMemo(() => {
|
||||
const agentFunctionIds = new Set(Object.keys(options.agentFunctions));
|
||||
|
||||
fields.push({
|
||||
id,
|
||||
description: "",
|
||||
entityId: "",
|
||||
isApprovalRequired: false,
|
||||
entityType: "Query",
|
||||
});
|
||||
setNewlyAddedId(id);
|
||||
}, [fields]);
|
||||
return agentFunctionIds;
|
||||
}, [options.agentFunctions]);
|
||||
|
||||
// Filter query items to exclude existing entities
|
||||
const filteredQueryItems = useMemo(() => {
|
||||
return options.Query.filter((item) => !existingEntityIds.has(item.value));
|
||||
}, [options.Query, existingEntityIds]);
|
||||
|
||||
// Filter JS collection items
|
||||
const filteredJSCollections = useMemo(() => {
|
||||
return options.JSCollections.map((collection) => ({
|
||||
...collection,
|
||||
// Filter out functions that are already used
|
||||
functions: collection.functions.filter(
|
||||
(func) => !existingEntityIds.has(func.value),
|
||||
),
|
||||
})).filter((collection) => collection.functions.length > 0);
|
||||
}, [options.JSCollections, existingEntityIds]);
|
||||
|
||||
const handleAddFunctionButtonClick = useCallback(
|
||||
(option: FunctionCallingEntityTypeOption) => {
|
||||
const id = uuid();
|
||||
|
||||
fields.push({
|
||||
id,
|
||||
description: "",
|
||||
entityId: option.value,
|
||||
isApprovalRequired: false,
|
||||
entityType: option.optionGroupType as FunctionCallingEntityType,
|
||||
});
|
||||
setNewlyAddedId(id);
|
||||
},
|
||||
[fields],
|
||||
);
|
||||
|
||||
const handleRemoveToolButtonClick = useCallback(
|
||||
(index: number) => {
|
||||
|
|
@ -54,17 +107,100 @@ export const FunctionCallingConfigForm = ({
|
|||
<>
|
||||
<Header>
|
||||
<Text isBold kind="heading-s" renderAs="p">
|
||||
Function calls
|
||||
Function Calls
|
||||
</Text>
|
||||
|
||||
<Button
|
||||
UNSAFE_width="110px"
|
||||
kind="secondary"
|
||||
onClick={handleAddFunctionButtonClick}
|
||||
startIcon="plus"
|
||||
>
|
||||
Add Function
|
||||
</Button>
|
||||
<Menu>
|
||||
<MenuTrigger>
|
||||
<Button UNSAFE_width="110px" kind="secondary" startIcon="plus">
|
||||
Add Function
|
||||
</Button>
|
||||
</MenuTrigger>
|
||||
<MenuContent align="end" loop width="235px">
|
||||
{/* Create new options */}
|
||||
<MenuGroup>
|
||||
<MenuItem onSelect={() => history.push(queryAddURL({}))}>
|
||||
<Flex alignItems="center" gap="spaces-2">
|
||||
<Icon name="plus" size="md" />
|
||||
New Query
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onSelect={() =>
|
||||
dispatch(
|
||||
createNewJSCollection(
|
||||
pageId,
|
||||
"AI_QUERY_FUNCTION_CALLING_CONFIG",
|
||||
"onToolCall",
|
||||
),
|
||||
)
|
||||
}
|
||||
>
|
||||
<Flex alignItems="center" gap="spaces-2">
|
||||
<Icon name="plus" size="md" />
|
||||
New JS Object
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
</MenuGroup>
|
||||
|
||||
{/* Query options group */}
|
||||
{options.Query.length > 0 && (
|
||||
<MenuGroup>
|
||||
{filteredQueryItems.map((option) => (
|
||||
<MenuItem
|
||||
key={option.value}
|
||||
onSelect={() => handleAddFunctionButtonClick(option)}
|
||||
>
|
||||
<Flex alignItems="center" gap="spaces-2">
|
||||
{option.icon &&
|
||||
(typeof option.icon === "string" ? (
|
||||
<Icon name={option.icon} size="md" />
|
||||
) : (
|
||||
option.icon
|
||||
))}
|
||||
{option.label}
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuGroup>
|
||||
)}
|
||||
|
||||
{/* JS Collections group with nested functions */}
|
||||
{options.JSCollections.length > 0 && (
|
||||
<MenuGroup>
|
||||
<MenuGroup>
|
||||
{filteredJSCollections.map((collection) => (
|
||||
<MenuSub key={collection.id}>
|
||||
<MenuSubTrigger>
|
||||
<Flex alignItems="center" gap="spaces-2">
|
||||
{collection.icon &&
|
||||
(typeof collection.icon === "string" ? (
|
||||
<Icon name={collection.icon} size="md" />
|
||||
) : (
|
||||
collection.icon
|
||||
))}
|
||||
{collection.name}
|
||||
</Flex>
|
||||
</MenuSubTrigger>
|
||||
<MenuSubContent>
|
||||
{collection.functions.map((jsFunction) => (
|
||||
<MenuItem
|
||||
key={jsFunction.value}
|
||||
onSelect={() =>
|
||||
handleAddFunctionButtonClick(jsFunction)
|
||||
}
|
||||
>
|
||||
{jsFunction.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuSubContent>
|
||||
</MenuSub>
|
||||
))}
|
||||
</MenuGroup>
|
||||
</MenuGroup>
|
||||
)}
|
||||
</MenuContent>
|
||||
</Menu>
|
||||
</Header>
|
||||
|
||||
{fields.length > 0 && (
|
||||
|
|
|
|||
|
|
@ -18,12 +18,8 @@ import type {
|
|||
FunctionCallingEntityType,
|
||||
FunctionCallingEntityTypeOption,
|
||||
} from "../types";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { useSelector } from "react-redux";
|
||||
import { selectEntityOptions } from "./selectors";
|
||||
import history from "utils/history";
|
||||
import { queryAddURL } from "ee/RouteBuilder";
|
||||
import { createNewJSCollection } from "actions/jsPaneActions";
|
||||
import { getCurrentPageId } from "selectors/editorSelectors";
|
||||
|
||||
interface FunctionCallingMenuFieldProps {
|
||||
children?: React.ReactNode;
|
||||
|
|
@ -86,9 +82,6 @@ const FunctionCallingMenuFieldRender = (props: FieldRenderProps) => {
|
|||
const { autoFocus, children, disabled, input, onValueChange } = props;
|
||||
const options = useSelector(selectEntityOptions);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const pageId = useSelector(getCurrentPageId);
|
||||
|
||||
// Get existing entity IDs from the agentFunctions, excluding the currently selected value
|
||||
const existingEntityIds = useMemo(() => {
|
||||
const agentFunctionIds = new Set(Object.keys(options.agentFunctions));
|
||||
|
|
@ -166,32 +159,6 @@ const FunctionCallingMenuFieldRender = (props: FieldRenderProps) => {
|
|||
</Button>
|
||||
</MenuTrigger>
|
||||
<MenuContent align="start" loop width="235px">
|
||||
{/* Create new options */}
|
||||
<MenuGroup>
|
||||
<MenuItem onSelect={() => history.push(queryAddURL({}))}>
|
||||
<Flex alignItems="center" gap="spaces-2">
|
||||
<Icon name="plus" size="md" />
|
||||
New Query
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onSelect={() =>
|
||||
dispatch(
|
||||
createNewJSCollection(
|
||||
pageId,
|
||||
"AI_QUERY_FUNCTION_CALLING_CONFIG",
|
||||
"onToolCall",
|
||||
),
|
||||
)
|
||||
}
|
||||
>
|
||||
<Flex alignItems="center" gap="spaces-2">
|
||||
<Icon name="plus" size="md" />
|
||||
New JS Object
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
</MenuGroup>
|
||||
|
||||
{/* Query options group */}
|
||||
{filteredQueryItems.length > 0 && (
|
||||
<MenuGroup>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user