@bikdotai/bik-component-library 0.0.849-beta.3 → 0.0.849-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/agent-builder/components/RestApiToolPanel.js +4 -4
- package/dist/cjs/components/agent-builder/components/RestApiToolPanel.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/VariableTriggerArea.js +4 -4
- package/dist/cjs/components/agent-builder/components/VariableTriggerArea.js.map +1 -1
- package/dist/esm/components/agent-builder/components/RestApiToolPanel.d.ts +9 -0
- package/dist/esm/components/agent-builder/components/RestApiToolPanel.js +121 -118
- package/dist/esm/components/agent-builder/components/RestApiToolPanel.js.map +1 -1
- package/dist/esm/components/agent-builder/components/VariableTriggerArea.d.ts +9 -0
- package/dist/esm/components/agent-builder/components/VariableTriggerArea.js +69 -45
- package/dist/esm/components/agent-builder/components/VariableTriggerArea.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),Q=require("../../../assets/icons/delete.svg.js"),K=require("../../../assets/icons/plus.svg.js"),o=require("react"),X=require("styled-components"),p=require("../../TypographyStyle.js"),i=require("../../../constants/Theme.js"),c=require("../AgentBuilder.styled.js"),Z=require("../constants/charLimits.js"),R=require("./DrawerHeaderText.js"),ee=require("./ToolInstructionsField.js"),h=require("./VariableTriggerArea.js"),te=require("../../side-modal/SideModal.js"),m=require("../../input/Input.js"),re=require("../../dropdown/Dropdown.js"),ne=require("../../dropdown/utils.js"),se=require("../../button/Button.js"),D=require("../../../editor/BikEditor.js"),oe=s=>s&&typeof s=="object"&&"default"in s?s:{default:s},O=oe(X),ae=["GET","POST","PUT","PATCH","DELETE"],le=ae.map(s=>({label:s,value:s})),C=(s,x)=>(x.textBefore.match(new RegExp('(?<!\\\\)"',"g"))?.length??0)%2===1?s:`"${s}"`,ie=({onClose:s,onSave:x,initial:a,onImprove:$,charLimits:q=Z.AGENT_CHAR_LIMITS,zIndex:M,existingNames:F=[],variablesData:d})=>{const[T,N]=o.useState(a?.name??""),I=o.useRef(null),k=o.useRef(null),[B,V]=o.useState(a?.instructions??""),[y,E]=o.useState(a?.url??"https://"),[g,z]=o.useState(a?.method??"POST"),[L,f]=o.useState(a?.headers??[{key:"",value:""}]),[A,J]=o.useState(a?.requestBody??""),[H,G]=o.useState(a?.responseSample??""),[w,P]=o.useState(!1),S=(t,r)=>f(n=>n.map((l,u)=>u===t?{...l,...r}:l)),U=()=>f(t=>[...t,{key:"",value:""}]),W=t=>f(r=>r.filter((n,l)=>l!==t)),j=T.trim(),v=j.length>0&&F.some(t=>t.trim().toLowerCase()===j.toLowerCase()),_=j.length>0&&y.trim().length>0&&!v,Y=async()=>{if(!_||w)return;const t={id:a?.id??`restapi_${Date.now().toString(36)}`,name:T.trim(),instructions:B,url:y.trim(),method:g,headers:L.filter(n=>n.key.trim()||n.value.trim()),requestBody:A,responseSample:H},r=x(t);if(r&&typeof r.then=="function"){P(!0);try{await r}finally{P(!1)}}};return e.jsxs(te.SideModal,{header:"Rest API",closeOnEscapeKey:!1,zIndex:M,headerCustomComponent:e.jsx(R.DrawerHeaderText,{title:"Rest API",subtitle:"Connect to any API endpoint. Define the request and a sample response for the agent to reference."}),width:"431px",headerStyle:R.DRAWER_HEADER_STYLE,bodyStyle:R.DRAWER_BODY_STYLE,onClose:s,saveButtonProps:{"data-test":"restapi-save",buttonText:"Save",buttonType:"primary",size:"small",disabled:!_,isLoading:w,onClick:Y},cancelButtonProps:{"data-test":"restapi-cancel",buttonText:"Cancel",buttonType:"tertiaryGray",size:"small",onClick:s},children:[e.jsx(m.Input,{"data-test":"restapi-name",variant:"small",labelText:"Name",labelTextBold:!0,placeholder:"Enter action name",value:T,maxCharLimit:q.name,state:v?"invalid":void 0,errorMessage:v?"A tool with this name already exists":void 0,onChangeText:N}),e.jsx(ee.ToolInstructionsField,{"data-test":"restapi-instructions",label:"Instructions",value:B,onChange:V,maxLength:q.instructions,placeholder:"Describe how should the LLM generate the rest API",onImprove:$,variablesData:d}),e.jsx(c.FieldBlock,{children:e.jsx(h.VariableTriggerArea,{variablesData:d,onInsert:(t,r)=>E(n=>{const l=r??n.length;return`${n.slice(0,l)}${t}${n.slice(l)}`}),children:e.jsx(m.Input,{"data-test":"restapi-url",variant:"small",labelText:"Request URL",labelTextBold:!0,placeholder:"https://",type:"url",value:y,onChangeText:E})})}),e.jsxs(c.FieldBlock,{children:[e.jsx(p.TitleSmall,{color:i.COLORS.content.primary,children:"HTTP method"}),e.jsx(re.Dropdown,{"data-test":"restapi-method",size:"small",width:"100%",dropdownWidth:"399px",options:le,defaultOptions:[{label:g,value:g}],onSelect:t=>{const r=ne.unwrapDropdownValue(t);r&&z(r)}})]}),e.jsxs(c.FieldBlock,{children:[e.jsx(p.TitleSmall,{color:i.COLORS.content.primary,children:"Headers"}),L.map((t,r)=>e.jsxs(de,{"data-test":`restapi-header-${r}`,children:[e.jsx(m.Input,{variant:"small",hideInputHeader:!0,placeholder:"Enter name",value:t.key,onChangeText:n=>S(r,{key:n})}),e.jsx(h.VariableTriggerArea,{variablesData:d,onInsert:(n,l)=>{const u=l??t.value.length;S(r,{value:`${t.value.slice(0,u)}${n}${t.value.slice(u)}`})},children:e.jsx(m.Input,{variant:"small",hideInputHeader:!0,placeholder:"Enter value",value:t.value,onChangeText:n=>S(r,{value:n})})}),e.jsx(ue,{type:"button","aria-label":"Remove header","data-test":`restapi-header-remove-${r}`,onClick:()=>W(r),children:e.jsx(Q.default,{width:16,height:16,color:i.COLORS.content.secondary})})]},r)),e.jsx(ce,{children:e.jsx(se.Button,{"data-test":"restapi-add-header",buttonType:"dashRegular",size:"small",LeadingIcon:K.default,buttonText:"Add header",onClick:U})})]}),e.jsxs(c.FieldBlock,{children:[e.jsx(p.TitleSmall,{color:i.COLORS.content.primary,children:"Request "}),e.jsx(h.VariableTriggerArea,{variablesData:d,transformToken:C,onInsert:t=>I.current?.insertInlineContent(t),children:e.jsx(D.BikEditor,{ref:I,features:{jsonMode:!0},initialContent:A,style:b,placeholder:"Type or paste JSON here",onChange:t=>J(t.text),minHeight:"120px",maxHeight:"240px"})})]}),e.jsxs(c.FieldBlock,{children:[e.jsx(p.TitleSmall,{color:i.COLORS.content.primary,children:"Response "}),e.jsx(h.VariableTriggerArea,{variablesData:d,transformToken:C,onInsert:t=>k.current?.insertInlineContent(t),children:e.jsx(D.BikEditor,{ref:k,features:{jsonMode:!0},style:b,initialContent:H,placeholder:"Type or paste JSON here",onChange:t=>G(t.text),minHeight:"120px",maxHeight:"240px"})})]})]})},de=O.default.div`
|
|
2
2
|
display: flex;
|
|
3
3
|
align-items: center;
|
|
4
4
|
gap: 8px;
|
|
5
|
-
`,
|
|
5
|
+
`,ce=O.default.div`
|
|
6
6
|
display: flex;
|
|
7
|
-
`,
|
|
7
|
+
`,ue=O.default.button`
|
|
8
8
|
display: inline-flex;
|
|
9
9
|
align-items: center;
|
|
10
10
|
justify-content: center;
|
|
@@ -19,5 +19,5 @@
|
|
|
19
19
|
&:hover {
|
|
20
20
|
border-color: ${i.COLORS.content.secondary};
|
|
21
21
|
}
|
|
22
|
-
`,
|
|
22
|
+
`,b={borderRadius:"4px",overflow:"hidden"};exports.JsonFieldBox=b;exports.RestApiToolPanel=ie;exports.jsonQuoteToken=C;
|
|
23
23
|
//# sourceMappingURL=RestApiToolPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RestApiToolPanel.js","sources":["../../../../../src/components/agent-builder/components/RestApiToolPanel.tsx"],"sourcesContent":["import DeleteIcon from '@src/assets/icons/delete.svg';\nimport PlusIcon from '@src/assets/icons/plus.svg';\nimport { BikEditor, BikEditorRef } from '@src/editor';\nimport React, { useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { Button } from '@src/components/button';\nimport { Dropdown, unwrapDropdownValue } from '@src/components/dropdown';\nimport { SingleOption } from '@src/components/dropdown/type';\nimport { Input } from '@src/components/input';\nimport { SideModal } from '@src/components/side-modal';\nimport { TitleSmall } from '@src/components/TypographyStyle';\nimport { COLORS } from '@src/constants/Theme';\nimport type { VariableListInterfaceV3 } from '../../variable-picker-v3/model';\nimport {\n\tRestApiHeader,\n\tRestApiMethod,\n\tRestApiToolConfig,\n} from '../AgentBuilder.model';\nimport { FieldBlock } from '../AgentBuilder.styled';\nimport type { AgentCharLimits } from '../constants/charLimits';\nimport { AGENT_CHAR_LIMITS } from '../constants/charLimits';\nimport {\n\tDRAWER_BODY_STYLE,\n\tDRAWER_HEADER_STYLE,\n\tDrawerHeaderText,\n} from './DrawerHeaderText';\nimport { ToolInstructionsField } from './ToolInstructionsField';\nimport { VariableTriggerArea } from './VariableTriggerArea';\n\ninterface RestApiToolPanelProps {\n\tonClose: () => void;\n\t/** Persist the config. A pending promise shows the Save loader. */\n\tonSave: (config: RestApiToolConfig) => void | Promise<void>;\n\t/** Seed values when editing an existing tool. */\n\tinitial?: RestApiToolConfig;\n\t/** Optional \"Improve with AI\" for the instructions field. Omit to hide it. */\n\tonImprove?: (text: string) => Promise<string>;\n\tcharLimits?: AgentCharLimits;\n\t/** SideModal stacking order — raise it when opened over another drawer. */\n\tzIndex?: number;\n\t/** Names of the OTHER tools — a new tool can't reuse one of these. */\n\texistingNames?: string[];\n\t/**\n\t * Variable catalog for the `@` trigger. When non-empty, `@` opens the\n\t * variable picker directly in Instructions / Request URL / header values /\n\t * Request / Response. Absent → the drawer behaves exactly as before.\n\t */\n\tvariablesData?: VariableListInterfaceV3[];\n}\n\nconst METHODS: RestApiMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];\nconst METHOD_OPTIONS: SingleOption[] = METHODS.map((m) => ({\n\tlabel: m,\n\tvalue: m,\n}));\n\n/**\n * Right-side drawer to configure a \"Rest API\" tool: the endpoint the agent can\n * call, plus a JSON request-body template and a sample response. Mount it fresh\n * per open (key it) so `initial` seeds the state. Built on the shared `SideModal`\n * shell and the BikEditor JSON body mode for the Request / Response editors.\n */\nexport const RestApiToolPanel: React.FC<RestApiToolPanelProps> = ({\n\tonClose,\n\tonSave,\n\tinitial,\n\tonImprove,\n\tcharLimits = AGENT_CHAR_LIMITS,\n\tzIndex,\n\texistingNames = [],\n\tvariablesData,\n}) => {\n\tconst [name, setName] = useState(initial?.name ?? '');\n\t// `@`-picked variables insert into the JSON editors at their own cursor.\n\tconst requestEditorRef = useRef<BikEditorRef>(null);\n\tconst responseEditorRef = useRef<BikEditorRef>(null);\n\tconst [instructions, setInstructions] = useState(initial?.instructions ?? '');\n\t// New tools start with the scheme pre-filled so the user only types the host.\n\tconst [url, setUrl] = useState(initial?.url ?? 'https://');\n\tconst [method, setMethod] = useState<RestApiMethod>(\n\t\tinitial?.method ?? 'POST',\n\t);\n\tconst [headers, setHeaders] = useState<RestApiHeader[]>(\n\t\tinitial?.headers ?? [{ key: '', value: '' }],\n\t);\n\tconst [requestBody, setRequestBody] = useState(initial?.requestBody ?? '');\n\tconst [responseSample, setResponseSample] = useState(\n\t\tinitial?.responseSample ?? '',\n\t);\n\tconst [saving, setSaving] = useState(false);\n\n\tconst patchHeader = (i: number, patch: Partial<RestApiHeader>) =>\n\t\tsetHeaders((prev) =>\n\t\t\tprev.map((h, idx) => (idx === i ? { ...h, ...patch } : h)),\n\t\t);\n\tconst addHeader = () =>\n\t\tsetHeaders((prev) => [...prev, { key: '', value: '' }]);\n\tconst removeHeader = (i: number) =>\n\t\tsetHeaders((prev) => prev.filter((_, idx) => idx !== i));\n\n\tconst nameTrimmed = name.trim();\n\t// Case-insensitive: two tools can't share a name (the LLM references them by it).\n\tconst isDuplicateName =\n\t\tnameTrimmed.length > 0 &&\n\t\texistingNames.some(\n\t\t\t(n) => n.trim().toLowerCase() === nameTrimmed.toLowerCase(),\n\t\t);\n\tconst canSave =\n\t\tnameTrimmed.length > 0 && url.trim().length > 0 && !isDuplicateName;\n\n\tconst handleSave = async () => {\n\t\tif (!canSave || saving) {\n\t\t\treturn;\n\t\t}\n\t\tconst config: RestApiToolConfig = {\n\t\t\tid: initial?.id ?? `restapi_${Date.now().toString(36)}`,\n\t\t\tname: name.trim(),\n\t\t\tinstructions,\n\t\t\turl: url.trim(),\n\t\t\tmethod,\n\t\t\t// Drop fully-empty header rows.\n\t\t\theaders: headers.filter((h) => h.key.trim() || h.value.trim()),\n\t\t\trequestBody,\n\t\t\tresponseSample,\n\t\t};\n\t\tconst result = onSave(config);\n\t\tif (result && typeof (result as Promise<void>).then === 'function') {\n\t\t\tsetSaving(true);\n\t\t\ttry {\n\t\t\t\tawait result;\n\t\t\t} finally {\n\t\t\t\tsetSaving(false);\n\t\t\t}\n\t\t}\n\t};\n\n\treturn (\n\t\t<SideModal\n\t\t\theader=\"Rest API\"\n\t\t\tcloseOnEscapeKey={false}\n\t\t\tzIndex={zIndex}\n\t\t\theaderCustomComponent={\n\t\t\t\t<DrawerHeaderText\n\t\t\t\t\ttitle=\"Rest API\"\n\t\t\t\t\tsubtitle=\"Connect to any API endpoint. Define the request and a sample response for the agent to reference.\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\twidth=\"431px\"\n\t\t\theaderStyle={DRAWER_HEADER_STYLE}\n\t\t\tbodyStyle={DRAWER_BODY_STYLE}\n\t\t\tonClose={onClose}\n\t\t\tsaveButtonProps={{\n\t\t\t\t'data-test': 'restapi-save',\n\t\t\t\tbuttonText: 'Save',\n\t\t\t\tbuttonType: 'primary',\n\t\t\t\tsize: 'small',\n\t\t\t\tdisabled: !canSave,\n\t\t\t\tisLoading: saving,\n\t\t\t\tonClick: handleSave,\n\t\t\t}}\n\t\t\tcancelButtonProps={{\n\t\t\t\t'data-test': 'restapi-cancel',\n\t\t\t\tbuttonText: 'Cancel',\n\t\t\t\tbuttonType: 'tertiaryGray',\n\t\t\t\tsize: 'small',\n\t\t\t\tonClick: onClose,\n\t\t\t}}\n\t\t>\n\t\t\t<Input\n\t\t\t\tdata-test=\"restapi-name\"\n\t\t\t\tvariant=\"small\"\n\t\t\t\tlabelText=\"Name\"\n\t\t\t\tlabelTextBold\n\t\t\t\tplaceholder=\"Enter action name\"\n\t\t\t\tvalue={name}\n\t\t\t\tmaxCharLimit={charLimits.name}\n\t\t\t\tstate={isDuplicateName ? 'invalid' : undefined}\n\t\t\t\terrorMessage={\n\t\t\t\t\tisDuplicateName ? 'A tool with this name already exists' : undefined\n\t\t\t\t}\n\t\t\t\tonChangeText={setName}\n\t\t\t/>\n\n\t\t\t<ToolInstructionsField\n\t\t\t\tdata-test=\"restapi-instructions\"\n\t\t\t\tlabel=\"Instructions\"\n\t\t\t\tvalue={instructions}\n\t\t\t\tonChange={setInstructions}\n\t\t\t\tmaxLength={charLimits.instructions}\n\t\t\t\tplaceholder=\"Describe how should the LLM generate the rest API\"\n\t\t\t\tonImprove={onImprove}\n\t\t\t\tvariablesData={variablesData}\n\t\t\t/>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\tonInsert={(token, caret) =>\n\t\t\t\t\t\tsetUrl((u) => {\n\t\t\t\t\t\t\tconst at = caret ?? u.length;\n\t\t\t\t\t\t\treturn `${u.slice(0, at)}${token}${u.slice(at)}`;\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tdata-test=\"restapi-url\"\n\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\tlabelText=\"Request URL\"\n\t\t\t\t\t\tlabelTextBold\n\t\t\t\t\t\tplaceholder=\"https://\"\n\t\t\t\t\t\ttype=\"url\"\n\t\t\t\t\t\tvalue={url}\n\t\t\t\t\t\tonChangeText={setUrl}\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>HTTP method</TitleSmall>\n\t\t\t\t<Dropdown\n\t\t\t\t\tdata-test=\"restapi-method\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\tdropdownWidth=\"399px\"\n\t\t\t\t\toptions={METHOD_OPTIONS}\n\t\t\t\t\tdefaultOptions={[{ label: method, value: method }]}\n\t\t\t\t\tonSelect={(opt) => {\n\t\t\t\t\t\tconst v = unwrapDropdownValue(opt);\n\t\t\t\t\t\tif (v) {\n\t\t\t\t\t\t\tsetMethod(v as RestApiMethod);\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Headers</TitleSmall>\n\t\t\t\t{headers.map((h, i) => (\n\t\t\t\t\t// eslint-disable-next-line react/no-array-index-key\n\t\t\t\t\t<HeaderRow key={i} data-test={`restapi-header-${i}`}>\n\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\t\thideInputHeader\n\t\t\t\t\t\t\tplaceholder=\"Enter name\"\n\t\t\t\t\t\t\tvalue={h.key}\n\t\t\t\t\t\t\tonChangeText={(v) => patchHeader(i, { key: v })}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<VariableTriggerArea\n\t\t\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\t\t\tonInsert={(token, caret) => {\n\t\t\t\t\t\t\t\tconst at = caret ?? h.value.length;\n\t\t\t\t\t\t\t\tpatchHeader(i, {\n\t\t\t\t\t\t\t\t\tvalue: `${h.value.slice(0, at)}${token}${h.value.slice(at)}`,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\t\t\thideInputHeader\n\t\t\t\t\t\t\t\tplaceholder=\"Enter value\"\n\t\t\t\t\t\t\t\tvalue={h.value}\n\t\t\t\t\t\t\t\tonChangeText={(v) => patchHeader(i, { value: v })}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</VariableTriggerArea>\n\t\t\t\t\t\t<IconBtn\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-label=\"Remove header\"\n\t\t\t\t\t\t\tdata-test={`restapi-header-remove-${i}`}\n\t\t\t\t\t\t\tonClick={() => removeHeader(i)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<DeleteIcon\n\t\t\t\t\t\t\t\twidth={16}\n\t\t\t\t\t\t\t\theight={16}\n\t\t\t\t\t\t\t\tcolor={COLORS.content.secondary}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</IconBtn>\n\t\t\t\t\t</HeaderRow>\n\t\t\t\t))}\n\t\t\t\t<AddHeaderRow>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tdata-test=\"restapi-add-header\"\n\t\t\t\t\t\tbuttonType=\"dashRegular\"\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\tLeadingIcon={PlusIcon}\n\t\t\t\t\t\tbuttonText=\"Add header\"\n\t\t\t\t\t\tonClick={addHeader}\n\t\t\t\t\t/>\n\t\t\t\t</AddHeaderRow>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Request </TitleSmall>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\tonInsert={(token) =>\n\t\t\t\t\t\trequestEditorRef.current?.insertInlineContent(token)\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<BikEditor\n\t\t\t\t\t\tref={requestEditorRef}\n\t\t\t\t\t\tfeatures={{ jsonMode: true }}\n\t\t\t\t\t\tinitialContent={requestBody}\n\t\t\t\t\t\tstyle={JsonFieldBox}\n\t\t\t\t\t\tplaceholder=\"Type or paste JSON here\"\n\t\t\t\t\t\tonChange={(c) => setRequestBody(c.text)}\n\t\t\t\t\t\tminHeight=\"120px\"\n\t\t\t\t\t\tmaxHeight=\"240px\"\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Response </TitleSmall>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\tonInsert={(token) =>\n\t\t\t\t\t\tresponseEditorRef.current?.insertInlineContent(token)\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<BikEditor\n\t\t\t\t\t\tref={responseEditorRef}\n\t\t\t\t\t\tfeatures={{ jsonMode: true }}\n\t\t\t\t\t\tstyle={JsonFieldBox}\n\t\t\t\t\t\tinitialContent={responseSample}\n\t\t\t\t\t\tplaceholder=\"Type or paste JSON here\"\n\t\t\t\t\t\tonChange={(c) => setResponseSample(c.text)}\n\t\t\t\t\t\tminHeight=\"120px\"\n\t\t\t\t\t\tmaxHeight=\"240px\"\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\t\t</SideModal>\n\t);\n};\n\nconst HeaderRow = styled.div`\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n`;\n\nconst AddHeaderRow = styled.div`\n\tdisplay: flex;\n`;\n\nconst IconBtn = styled.button`\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tflex-shrink: 0;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid ${COLORS.stroke.primary};\n\tborder-radius: 4px;\n\tbackground: ${COLORS.surface.standard};\n\tcursor: pointer;\n\n\t&:hover {\n\t\tborder-color: ${COLORS.content.secondary};\n\t}\n`;\n\nexport const JsonFieldBox = {\n\tborderRadius: '4px',\n\toverflow: 'hidden',\n};\n"],"names":["METHODS","METHOD_OPTIONS","m","RestApiToolPanel","onClose","onSave","initial","onImprove","charLimits","AGENT_CHAR_LIMITS","zIndex","existingNames","variablesData","name","setName","useState","requestEditorRef","useRef","responseEditorRef","instructions","setInstructions","url","setUrl","method","setMethod","headers","setHeaders","requestBody","setRequestBody","responseSample","setResponseSample","saving","setSaving","patchHeader","i","patch","prev","h","idx","addHeader","removeHeader","_","nameTrimmed","isDuplicateName","n","canSave","handleSave","config","result","jsxs","SideModal","jsx","DrawerHeaderText","DRAWER_HEADER_STYLE","DRAWER_BODY_STYLE","Input","ToolInstructionsField","FieldBlock","VariableTriggerArea","token","caret","u","at","TitleSmall","COLORS","Dropdown","opt","v","unwrapDropdownValue","HeaderRow","IconBtn","DeleteIcon","AddHeaderRow","Button","PlusIcon","BikEditor","JsonFieldBox","c","styled"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RestApiToolPanel.js","sources":["../../../../../src/components/agent-builder/components/RestApiToolPanel.tsx"],"sourcesContent":["import DeleteIcon from '@src/assets/icons/delete.svg';\nimport PlusIcon from '@src/assets/icons/plus.svg';\nimport { BikEditor, BikEditorRef } from '@src/editor';\nimport React, { useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { Button } from '@src/components/button';\nimport { Dropdown, unwrapDropdownValue } from '@src/components/dropdown';\nimport { SingleOption } from '@src/components/dropdown/type';\nimport { Input } from '@src/components/input';\nimport { SideModal } from '@src/components/side-modal';\nimport { TitleSmall } from '@src/components/TypographyStyle';\nimport { COLORS } from '@src/constants/Theme';\nimport type { VariableListInterfaceV3 } from '../../variable-picker-v3/model';\nimport {\n\tRestApiHeader,\n\tRestApiMethod,\n\tRestApiToolConfig,\n} from '../AgentBuilder.model';\nimport { FieldBlock } from '../AgentBuilder.styled';\nimport type { AgentCharLimits } from '../constants/charLimits';\nimport { AGENT_CHAR_LIMITS } from '../constants/charLimits';\nimport {\n\tDRAWER_BODY_STYLE,\n\tDRAWER_HEADER_STYLE,\n\tDrawerHeaderText,\n} from './DrawerHeaderText';\nimport { ToolInstructionsField } from './ToolInstructionsField';\nimport { VariableTriggerArea } from './VariableTriggerArea';\n\ninterface RestApiToolPanelProps {\n\tonClose: () => void;\n\t/** Persist the config. A pending promise shows the Save loader. */\n\tonSave: (config: RestApiToolConfig) => void | Promise<void>;\n\t/** Seed values when editing an existing tool. */\n\tinitial?: RestApiToolConfig;\n\t/** Optional \"Improve with AI\" for the instructions field. Omit to hide it. */\n\tonImprove?: (text: string) => Promise<string>;\n\tcharLimits?: AgentCharLimits;\n\t/** SideModal stacking order — raise it when opened over another drawer. */\n\tzIndex?: number;\n\t/** Names of the OTHER tools — a new tool can't reuse one of these. */\n\texistingNames?: string[];\n\t/**\n\t * Variable catalog for the `@` trigger. When non-empty, `@` opens the\n\t * variable picker directly in Instructions / Request URL / header values /\n\t * Request / Response. Absent → the drawer behaves exactly as before.\n\t */\n\tvariablesData?: VariableListInterfaceV3[];\n}\n\nconst METHODS: RestApiMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];\nconst METHOD_OPTIONS: SingleOption[] = METHODS.map((m) => ({\n\tlabel: m,\n\tvalue: m,\n}));\n\n/**\n * Keep the Request / Response bodies valid JSON: wrap the picked token in\n * quotes (`\"email\": \"{{variable:customer.email}}\"`) — unless the `@` was typed\n * inside a string literal already (odd number of unescaped `\"` before it, e.g.\n * `\"Bearer @`), where the bare token interpolates into the existing string.\n */\nexport const jsonQuoteToken = (\n\ttoken: string,\n\tctx: { textBefore: string },\n): string => {\n\tconst quotes = ctx.textBefore.match(/(?<!\\\\)\"/g)?.length ?? 0;\n\treturn quotes % 2 === 1 ? token : `\"${token}\"`;\n};\n\n/**\n * Right-side drawer to configure a \"Rest API\" tool: the endpoint the agent can\n * call, plus a JSON request-body template and a sample response. Mount it fresh\n * per open (key it) so `initial` seeds the state. Built on the shared `SideModal`\n * shell and the BikEditor JSON body mode for the Request / Response editors.\n */\nexport const RestApiToolPanel: React.FC<RestApiToolPanelProps> = ({\n\tonClose,\n\tonSave,\n\tinitial,\n\tonImprove,\n\tcharLimits = AGENT_CHAR_LIMITS,\n\tzIndex,\n\texistingNames = [],\n\tvariablesData,\n}) => {\n\tconst [name, setName] = useState(initial?.name ?? '');\n\t// `@`-picked variables insert into the JSON editors at their own cursor.\n\tconst requestEditorRef = useRef<BikEditorRef>(null);\n\tconst responseEditorRef = useRef<BikEditorRef>(null);\n\tconst [instructions, setInstructions] = useState(initial?.instructions ?? '');\n\t// New tools start with the scheme pre-filled so the user only types the host.\n\tconst [url, setUrl] = useState(initial?.url ?? 'https://');\n\tconst [method, setMethod] = useState<RestApiMethod>(\n\t\tinitial?.method ?? 'POST',\n\t);\n\tconst [headers, setHeaders] = useState<RestApiHeader[]>(\n\t\tinitial?.headers ?? [{ key: '', value: '' }],\n\t);\n\tconst [requestBody, setRequestBody] = useState(initial?.requestBody ?? '');\n\tconst [responseSample, setResponseSample] = useState(\n\t\tinitial?.responseSample ?? '',\n\t);\n\tconst [saving, setSaving] = useState(false);\n\n\tconst patchHeader = (i: number, patch: Partial<RestApiHeader>) =>\n\t\tsetHeaders((prev) =>\n\t\t\tprev.map((h, idx) => (idx === i ? { ...h, ...patch } : h)),\n\t\t);\n\tconst addHeader = () =>\n\t\tsetHeaders((prev) => [...prev, { key: '', value: '' }]);\n\tconst removeHeader = (i: number) =>\n\t\tsetHeaders((prev) => prev.filter((_, idx) => idx !== i));\n\n\tconst nameTrimmed = name.trim();\n\t// Case-insensitive: two tools can't share a name (the LLM references them by it).\n\tconst isDuplicateName =\n\t\tnameTrimmed.length > 0 &&\n\t\texistingNames.some(\n\t\t\t(n) => n.trim().toLowerCase() === nameTrimmed.toLowerCase(),\n\t\t);\n\tconst canSave =\n\t\tnameTrimmed.length > 0 && url.trim().length > 0 && !isDuplicateName;\n\n\tconst handleSave = async () => {\n\t\tif (!canSave || saving) {\n\t\t\treturn;\n\t\t}\n\t\tconst config: RestApiToolConfig = {\n\t\t\tid: initial?.id ?? `restapi_${Date.now().toString(36)}`,\n\t\t\tname: name.trim(),\n\t\t\tinstructions,\n\t\t\turl: url.trim(),\n\t\t\tmethod,\n\t\t\t// Drop fully-empty header rows.\n\t\t\theaders: headers.filter((h) => h.key.trim() || h.value.trim()),\n\t\t\trequestBody,\n\t\t\tresponseSample,\n\t\t};\n\t\tconst result = onSave(config);\n\t\tif (result && typeof (result as Promise<void>).then === 'function') {\n\t\t\tsetSaving(true);\n\t\t\ttry {\n\t\t\t\tawait result;\n\t\t\t} finally {\n\t\t\t\tsetSaving(false);\n\t\t\t}\n\t\t}\n\t};\n\n\treturn (\n\t\t<SideModal\n\t\t\theader=\"Rest API\"\n\t\t\tcloseOnEscapeKey={false}\n\t\t\tzIndex={zIndex}\n\t\t\theaderCustomComponent={\n\t\t\t\t<DrawerHeaderText\n\t\t\t\t\ttitle=\"Rest API\"\n\t\t\t\t\tsubtitle=\"Connect to any API endpoint. Define the request and a sample response for the agent to reference.\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\twidth=\"431px\"\n\t\t\theaderStyle={DRAWER_HEADER_STYLE}\n\t\t\tbodyStyle={DRAWER_BODY_STYLE}\n\t\t\tonClose={onClose}\n\t\t\tsaveButtonProps={{\n\t\t\t\t'data-test': 'restapi-save',\n\t\t\t\tbuttonText: 'Save',\n\t\t\t\tbuttonType: 'primary',\n\t\t\t\tsize: 'small',\n\t\t\t\tdisabled: !canSave,\n\t\t\t\tisLoading: saving,\n\t\t\t\tonClick: handleSave,\n\t\t\t}}\n\t\t\tcancelButtonProps={{\n\t\t\t\t'data-test': 'restapi-cancel',\n\t\t\t\tbuttonText: 'Cancel',\n\t\t\t\tbuttonType: 'tertiaryGray',\n\t\t\t\tsize: 'small',\n\t\t\t\tonClick: onClose,\n\t\t\t}}\n\t\t>\n\t\t\t<Input\n\t\t\t\tdata-test=\"restapi-name\"\n\t\t\t\tvariant=\"small\"\n\t\t\t\tlabelText=\"Name\"\n\t\t\t\tlabelTextBold\n\t\t\t\tplaceholder=\"Enter action name\"\n\t\t\t\tvalue={name}\n\t\t\t\tmaxCharLimit={charLimits.name}\n\t\t\t\tstate={isDuplicateName ? 'invalid' : undefined}\n\t\t\t\terrorMessage={\n\t\t\t\t\tisDuplicateName ? 'A tool with this name already exists' : undefined\n\t\t\t\t}\n\t\t\t\tonChangeText={setName}\n\t\t\t/>\n\n\t\t\t<ToolInstructionsField\n\t\t\t\tdata-test=\"restapi-instructions\"\n\t\t\t\tlabel=\"Instructions\"\n\t\t\t\tvalue={instructions}\n\t\t\t\tonChange={setInstructions}\n\t\t\t\tmaxLength={charLimits.instructions}\n\t\t\t\tplaceholder=\"Describe how should the LLM generate the rest API\"\n\t\t\t\tonImprove={onImprove}\n\t\t\t\tvariablesData={variablesData}\n\t\t\t/>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\tonInsert={(token, caret) =>\n\t\t\t\t\t\tsetUrl((u) => {\n\t\t\t\t\t\t\tconst at = caret ?? u.length;\n\t\t\t\t\t\t\treturn `${u.slice(0, at)}${token}${u.slice(at)}`;\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tdata-test=\"restapi-url\"\n\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\tlabelText=\"Request URL\"\n\t\t\t\t\t\tlabelTextBold\n\t\t\t\t\t\tplaceholder=\"https://\"\n\t\t\t\t\t\ttype=\"url\"\n\t\t\t\t\t\tvalue={url}\n\t\t\t\t\t\tonChangeText={setUrl}\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>HTTP method</TitleSmall>\n\t\t\t\t<Dropdown\n\t\t\t\t\tdata-test=\"restapi-method\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\tdropdownWidth=\"399px\"\n\t\t\t\t\toptions={METHOD_OPTIONS}\n\t\t\t\t\tdefaultOptions={[{ label: method, value: method }]}\n\t\t\t\t\tonSelect={(opt) => {\n\t\t\t\t\t\tconst v = unwrapDropdownValue(opt);\n\t\t\t\t\t\tif (v) {\n\t\t\t\t\t\t\tsetMethod(v as RestApiMethod);\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Headers</TitleSmall>\n\t\t\t\t{headers.map((h, i) => (\n\t\t\t\t\t// eslint-disable-next-line react/no-array-index-key\n\t\t\t\t\t<HeaderRow key={i} data-test={`restapi-header-${i}`}>\n\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\t\thideInputHeader\n\t\t\t\t\t\t\tplaceholder=\"Enter name\"\n\t\t\t\t\t\t\tvalue={h.key}\n\t\t\t\t\t\t\tonChangeText={(v) => patchHeader(i, { key: v })}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<VariableTriggerArea\n\t\t\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\t\t\tonInsert={(token, caret) => {\n\t\t\t\t\t\t\t\tconst at = caret ?? h.value.length;\n\t\t\t\t\t\t\t\tpatchHeader(i, {\n\t\t\t\t\t\t\t\t\tvalue: `${h.value.slice(0, at)}${token}${h.value.slice(at)}`,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\t\t\thideInputHeader\n\t\t\t\t\t\t\t\tplaceholder=\"Enter value\"\n\t\t\t\t\t\t\t\tvalue={h.value}\n\t\t\t\t\t\t\t\tonChangeText={(v) => patchHeader(i, { value: v })}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</VariableTriggerArea>\n\t\t\t\t\t\t<IconBtn\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-label=\"Remove header\"\n\t\t\t\t\t\t\tdata-test={`restapi-header-remove-${i}`}\n\t\t\t\t\t\t\tonClick={() => removeHeader(i)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<DeleteIcon\n\t\t\t\t\t\t\t\twidth={16}\n\t\t\t\t\t\t\t\theight={16}\n\t\t\t\t\t\t\t\tcolor={COLORS.content.secondary}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</IconBtn>\n\t\t\t\t\t</HeaderRow>\n\t\t\t\t))}\n\t\t\t\t<AddHeaderRow>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tdata-test=\"restapi-add-header\"\n\t\t\t\t\t\tbuttonType=\"dashRegular\"\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\tLeadingIcon={PlusIcon}\n\t\t\t\t\t\tbuttonText=\"Add header\"\n\t\t\t\t\t\tonClick={addHeader}\n\t\t\t\t\t/>\n\t\t\t\t</AddHeaderRow>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Request </TitleSmall>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\ttransformToken={jsonQuoteToken}\n\t\t\t\t\tonInsert={(token) =>\n\t\t\t\t\t\trequestEditorRef.current?.insertInlineContent(token)\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<BikEditor\n\t\t\t\t\t\tref={requestEditorRef}\n\t\t\t\t\t\tfeatures={{ jsonMode: true }}\n\t\t\t\t\t\tinitialContent={requestBody}\n\t\t\t\t\t\tstyle={JsonFieldBox}\n\t\t\t\t\t\tplaceholder=\"Type or paste JSON here\"\n\t\t\t\t\t\tonChange={(c) => setRequestBody(c.text)}\n\t\t\t\t\t\tminHeight=\"120px\"\n\t\t\t\t\t\tmaxHeight=\"240px\"\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Response </TitleSmall>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\ttransformToken={jsonQuoteToken}\n\t\t\t\t\tonInsert={(token) =>\n\t\t\t\t\t\tresponseEditorRef.current?.insertInlineContent(token)\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<BikEditor\n\t\t\t\t\t\tref={responseEditorRef}\n\t\t\t\t\t\tfeatures={{ jsonMode: true }}\n\t\t\t\t\t\tstyle={JsonFieldBox}\n\t\t\t\t\t\tinitialContent={responseSample}\n\t\t\t\t\t\tplaceholder=\"Type or paste JSON here\"\n\t\t\t\t\t\tonChange={(c) => setResponseSample(c.text)}\n\t\t\t\t\t\tminHeight=\"120px\"\n\t\t\t\t\t\tmaxHeight=\"240px\"\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\t\t</SideModal>\n\t);\n};\n\nconst HeaderRow = styled.div`\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n`;\n\nconst AddHeaderRow = styled.div`\n\tdisplay: flex;\n`;\n\nconst IconBtn = styled.button`\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tflex-shrink: 0;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid ${COLORS.stroke.primary};\n\tborder-radius: 4px;\n\tbackground: ${COLORS.surface.standard};\n\tcursor: pointer;\n\n\t&:hover {\n\t\tborder-color: ${COLORS.content.secondary};\n\t}\n`;\n\nexport const JsonFieldBox = {\n\tborderRadius: '4px',\n\toverflow: 'hidden',\n};\n"],"names":["METHODS","METHOD_OPTIONS","m","jsonQuoteToken","token","ctx","RestApiToolPanel","onClose","onSave","initial","onImprove","charLimits","AGENT_CHAR_LIMITS","zIndex","existingNames","variablesData","name","setName","useState","requestEditorRef","useRef","responseEditorRef","instructions","setInstructions","url","setUrl","method","setMethod","headers","setHeaders","requestBody","setRequestBody","responseSample","setResponseSample","saving","setSaving","patchHeader","i","patch","prev","h","idx","addHeader","removeHeader","_","nameTrimmed","isDuplicateName","n","canSave","handleSave","config","result","jsxs","SideModal","jsx","DrawerHeaderText","DRAWER_HEADER_STYLE","DRAWER_BODY_STYLE","Input","ToolInstructionsField","FieldBlock","VariableTriggerArea","caret","u","at","TitleSmall","COLORS","Dropdown","opt","v","unwrapDropdownValue","HeaderRow","IconBtn","DeleteIcon","AddHeaderRow","Button","PlusIcon","BikEditor","JsonFieldBox","c","styled"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("react/jsx-runtime"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("react/jsx-runtime"),u=require("react"),h=require("styled-components"),k=require("../../variable-picker-v3/model.js"),w=require("../utils/mentionSerialization.js"),y=require("../../variable-picker-v3/VariablePicker.js"),T=e=>e&&typeof e=="object"&&"default"in e?e:{default:e},v=T(h),p=e=>`{{variable:${w.variableTokenName(e.actualValue)}}}`,g=/[\s,;:/?&=(){}[\]"'<>]/,B=e=>{if(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement){const t=e.selectionStart??e.value.length,i=t===0?" ":e.value[t-1]??" ";return{ok:g.test(i),caret:t,textBefore:e.value.slice(0,t)}}const l=window.getSelection(),a=l?.anchorNode?.textContent??"",c=l?.anchorOffset??0,s=c===0?" ":a[c-1]??" ";return{ok:g.test(s),caret:null,textBefore:a.slice(0,c)}},R=({variablesData:e,onInsert:l,transformToken:a,children:c})=>{const s=u.useRef(null),[t,i]=u.useState(null),f=(e?.length??0)>0,b=u.useCallback(o=>{if(!f||o.key!=="@")return;const r=B(o.target);if(!r.ok)return;o.preventDefault(),o.stopPropagation();const n=s.current?.getBoundingClientRect(),m=!!n&&window.innerHeight-n.bottom<340,x=!!n&&window.innerWidth-n.left<360;i({caret:r.caret,textBefore:r.textBefore,above:m,alignRight:x})},[f]);return u.useEffect(()=>{if(!t)return;const o=n=>{n.key==="Escape"&&(n.stopPropagation(),i(null))},r=n=>{s.current?.contains(n.target)||i(null)};return document.addEventListener("keydown",o,!0),document.addEventListener("mousedown",r),()=>{document.removeEventListener("keydown",o,!0),document.removeEventListener("mousedown",r)}},[t]),d.jsxs(E,{ref:s,onKeyDownCapture:b,children:[c,t&&d.jsx(C,{$above:t.above,$right:t.alignRight,"data-test":"variable-trigger-panel",children:d.jsx(y.VariablePicker,{type:k.PickerType.FLOATER,data:e??[],showRecommendedBar:!1,onClose:()=>i(null),onSelect:o=>{i(null);const r=p(o),n=a?a(r,{textBefore:t.textBefore}):r;l(n,t.caret)}})})]})},E=v.default.div`
|
|
2
2
|
position: relative;
|
|
3
|
-
`,
|
|
3
|
+
`,C=v.default.div`
|
|
4
4
|
position: absolute;
|
|
5
|
-
left: 0;
|
|
6
5
|
z-index: 1000;
|
|
6
|
+
${e=>e.$right?"right: 0;":"left: 0;"}
|
|
7
7
|
${e=>e.$above?"bottom: calc(100% + 4px);":"top: calc(100% + 4px);"}
|
|
8
|
-
`;exports.VariableTriggerArea=
|
|
8
|
+
`;exports.VariableTriggerArea=R;exports.variableToken=p;
|
|
9
9
|
//# sourceMappingURL=VariableTriggerArea.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VariableTriggerArea.js","sources":["../../../../../src/components/agent-builder/components/VariableTriggerArea.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { VariablePicker } from '../../variable-picker-v3';\nimport { PickerType } from '../../variable-picker-v3/model';\nimport type {\n\tVariableListInterfaceV3,\n\tVariableV3,\n} from '../../variable-picker-v3/model';\nimport { variableTokenName } from '../utils/mentionSerialization';\n\n/** The persisted form of a picked variable (`{{variable:<name>}}`). */\nexport const variableToken = (variable: VariableV3): string =>\n\t`{{variable:${variableTokenName(variable.actualValue)}}}`;\n\n/**\n * Boundary test for the `@` trigger: an `@` typed at the start of the field or\n * after a separator opens the picker. The separator set covers URL and JSON\n * delimiters too (`https://@`, `Bearer=@`, `\"@`, `[@`) — an email address's `@`\n * always follows a letter / digit / dot, so `john@acme.com` still types\n * through untouched. Returns the caret index for input / textarea targets\n * (where the caller can splice the token in), null for contenteditable ones.\n */\nconst BOUNDARY = /[\\s,;:/?&=(){}[\\]\"'<>]/;\n\nconst triggerContext = (\n\ttarget: EventTarget | null,\n): { ok: boolean; caret: number | null } => {\n\tif (\n\t\ttarget instanceof HTMLInputElement ||\n\t\ttarget instanceof HTMLTextAreaElement\n\t) {\n\t\tconst caret = target.selectionStart ?? target.value.length;\n\t\tconst prev = caret === 0 ? ' ' : target.value[caret - 1] ?? ' ';\n\t\treturn { ok: BOUNDARY.test(prev), caret };\n\t}\n\t// Rich editor (ProseMirror contenteditable): read the character before the\n\t// selection.\n\tconst sel = window.getSelection();\n\tconst text = sel?.anchorNode?.textContent ?? '';\n\tconst offset = sel?.anchorOffset ?? 0;\n\tconst prev = offset === 0 ? ' ' : text[offset - 1] ?? ' ';\n\treturn { ok: BOUNDARY.test(prev), caret: null };\n};\n\ninterface VariableTriggerAreaProps {\n\t/** Variable catalog. Absent / empty → the wrapper is inert (children only). */\n\tvariablesData?: VariableListInterfaceV3[];\n\t/**\n\t * Insert `token` into the wrapped field. `caret` is the character index the\n\t * `@` was typed at (input / textarea targets — splice the token in there);\n\t * null for rich-editor targets (insert at the editor's own cursor).\n\t */\n\tonInsert: (token: string, caret: number | null) => void;\n\tchildren: React.ReactNode;\n}\n\n/**\n * Wraps any plain field (input / textarea / chips entry / BikEditor) and opens\n * the shared {@link VariablePicker} as a floating panel when `@` is typed at a\n * word boundary. The `@` keystroke itself is swallowed (never reaches the\n * field); picking a variable calls `onInsert` with the `{{variable:<name>}}`\n * token, and Escape / click-outside / the panel's ✕ just closes the panel.\n *\n * Purely presentational wrapper — it renders a `position: relative` block, so\n * the wrapped field must be happy inside a plain block container.\n */\nexport const VariableTriggerArea: React.FC<VariableTriggerAreaProps> = ({\n\tvariablesData,\n\tonInsert,\n\tchildren,\n}) => {\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\t// Non-null while the panel is open: where to put the token when picked, and\n\t// whether the panel renders above the field (not enough room below).\n\tconst [trigger, setTrigger] = useState<{\n\t\tcaret: number | null;\n\t\tabove: boolean;\n\t} | null>(null);\n\n\tconst enabled = (variablesData?.length ?? 0) > 0;\n\n\tconst onKeyDownCapture = useCallback(\n\t\t(e: React.KeyboardEvent) => {\n\t\t\tif (!enabled || e.key !== '@') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst ctx = triggerContext(e.target);\n\t\t\tif (!ctx.ok) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Swallow the `@` so the field's value stays untouched while picking.\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tconst rect = containerRef.current?.getBoundingClientRect();\n\t\t\tconst above = !!rect && window.innerHeight - rect.bottom < 340;\n\t\t\tsetTrigger({ caret: ctx.caret, above });\n\t\t},\n\t\t[enabled],\n\t);\n\n\t// Escape / click-outside dismiss, active only while open.\n\tuseEffect(() => {\n\t\tif (!trigger) {\n\t\t\treturn;\n\t\t}\n\t\tconst onKey = (e: KeyboardEvent) => {\n\t\t\tif (e.key === 'Escape') {\n\t\t\t\te.stopPropagation();\n\t\t\t\tsetTrigger(null);\n\t\t\t}\n\t\t};\n\t\tconst onDown = (e: MouseEvent) => {\n\t\t\tif (!containerRef.current?.contains(e.target as Node)) {\n\t\t\t\tsetTrigger(null);\n\t\t\t}\n\t\t};\n\t\t// Capture phase so an Escape meant for the panel never also closes the\n\t\t// drawer underneath.\n\t\tdocument.addEventListener('keydown', onKey, true);\n\t\tdocument.addEventListener('mousedown', onDown);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('keydown', onKey, true);\n\t\t\tdocument.removeEventListener('mousedown', onDown);\n\t\t};\n\t}, [trigger]);\n\n\treturn (\n\t\t<TriggerWrap ref={containerRef} onKeyDownCapture={onKeyDownCapture}>\n\t\t\t{children}\n\t\t\t{trigger && (\n\t\t\t\t<FloaterBox $above={trigger.above} data-test=\"variable-trigger-panel\">\n\t\t\t\t\t<VariablePicker\n\t\t\t\t\t\ttype={PickerType.FLOATER}\n\t\t\t\t\t\tdata={variablesData ?? []}\n\t\t\t\t\t\tshowRecommendedBar={false}\n\t\t\t\t\t\tonClose={() => setTrigger(null)}\n\t\t\t\t\t\tonSelect={(variable: VariableV3) => {\n\t\t\t\t\t\t\tsetTrigger(null);\n\t\t\t\t\t\t\tonInsert(variableToken(variable), trigger.caret);\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</FloaterBox>\n\t\t\t)}\n\t\t</TriggerWrap>\n\t);\n};\n\nconst TriggerWrap = styled.div`\n\tposition: relative;\n`;\n\n// Floats under (or over) the wrapped field; VariablePicker brings its own card\n// styling. High z-index: these fields live inside side-modal drawers.\nconst FloaterBox = styled.div<{ $above: boolean }>`\n\tposition: absolute;\n\tleft: 0;\n\tz-index: 1000;\n\t${(p) => (p.$above ? 'bottom: calc(100% + 4px);' : 'top: calc(100% + 4px);')}\n`;\n"],"names":["variableToken","variable","variableTokenName","BOUNDARY","triggerContext","target","caret","prev","sel","text","offset","VariableTriggerArea","variablesData","onInsert","children","containerRef","useRef","trigger","setTrigger","useState","enabled","onKeyDownCapture","useCallback","e","ctx","rect","above","useEffect","onKey","onDown","jsxs","TriggerWrap","jsx","FloaterBox","VariablePicker","PickerType","styled","p"],"mappings":"2XAWaA,EAAiBC,GAC7B,cAAcC,EAAAA,kBAAkBD,EAAS,WAAW,CAAC,KAUhDE,EAAW,yBAEXC,EACLC,GAC2C,CAC3C,GACCA,aAAkB,kBAClBA,aAAkB,oBACjB,CACD,MAAMC,EAAQD,EAAO,gBAAkBA,EAAO,MAAM,OAC9CE,EAAOD,IAAU,EAAI,IAAMD,EAAO,MAAMC,EAAQ,CAAC,GAAK,IAC5D,MAAO,CAAE,GAAIH,EAAS,KAAKI,CAAI,EAAG,MAAAD,CAAA,CACnC,CAGA,MAAME,EAAM,OAAO,aAAA,EACbC,EAAOD,GAAK,YAAY,aAAe,GACvCE,EAASF,GAAK,cAAgB,EAC9BD,EAAOG,IAAW,EAAI,IAAMD,EAAKC,EAAS,CAAC,GAAK,IACtD,MAAO,CAAE,GAAIP,EAAS,KAAKI,CAAI,EAAG,MAAO,IAAA,CAC1C,EAwBaI,EAA0D,CAAC,CACvE,cAAAC,EACA,SAAAC,EACA,SAAAC,CACD,IAAM,CACL,MAAMC,EAAeC,EAAAA,OAAuB,IAAI,EAG1C,CAACC,EAASC,CAAU,EAAIC,EAAAA,SAGpB,IAAI,EAERC,GAAWR,GAAe,QAAU,GAAK,EAEzCS,EAAmBC,EAAAA,YACvBC,GAA2B,CAC3B,GAAI,CAACH,GAAWG,EAAE,MAAQ,IACzB,OAED,MAAMC,EAAMpB,EAAemB,EAAE,MAAM,EACnC,GAAI,CAACC,EAAI,GACR,OAGDD,EAAE,eAAA,EACFA,EAAE,gBAAA,EACF,MAAME,EAAOV,EAAa,SAAS,sBAAA,EAC7BW,EAAQ,CAAC,CAACD,GAAQ,OAAO,YAAcA,EAAK,OAAS,IAC3DP,EAAW,CAAE,MAAOM,EAAI,MAAO,MAAAE,EAAO,CACvC,EACA,CAACN,CAAO,CAAA,EAITO,OAAAA,EAAAA,UAAU,IAAM,CACf,GAAI,CAACV,EACJ,OAED,MAAMW,EAASL,GAAqB,CAC/BA,EAAE,MAAQ,WACbA,EAAE,gBAAA,EACFL,EAAW,IAAI,EAEjB,EACMW,EAAUN,GAAkB,CAC5BR,EAAa,SAAS,SAASQ,EAAE,MAAc,GACnDL,EAAW,IAAI,CAEjB,EAGA,gBAAS,iBAAiB,UAAWU,EAAO,EAAI,EAChD,SAAS,iBAAiB,YAAaC,CAAM,EACtC,IAAM,CACZ,SAAS,oBAAoB,UAAWD,EAAO,EAAI,EACnD,SAAS,oBAAoB,YAAaC,CAAM,CACjD,CACD,EAAG,CAACZ,CAAO,CAAC,EAGXa,EAAAA,KAACC,EAAA,CAAY,IAAKhB,EAAc,iBAAAM,EAC9B,SAAA,CAAAP,EACAG,GACAe,EAAAA,IAACC,EAAA,CAAW,OAAQhB,EAAQ,MAAO,YAAU,yBAC5C,SAAAe,EAAAA,IAACE,EAAAA,eAAA,CACA,KAAMC,EAAAA,WAAW,QACjB,KAAMvB,GAAiB,CAAA,EACvB,mBAAoB,GACpB,QAAS,IAAMM,EAAW,IAAI,EAC9B,SAAWjB,GAAyB,CACnCiB,EAAW,IAAI,EACfL,EAASb,EAAcC,CAAQ,EAAGgB,EAAQ,KAAK,CAChD,CAAA,CAAA,CACD,CACD,CAAA,EAEF,CAEF,EAEMc,EAAcK,EAAAA,QAAO;AAAA;AAAA,EAMrBH,EAAaG,EAAAA,QAAO;AAAA;AAAA;AAAA;AAAA,GAItBC,GAAOA,EAAE,OAAS,4BAA8B,wBAAyB;AAAA"}
|
|
1
|
+
{"version":3,"file":"VariableTriggerArea.js","sources":["../../../../../src/components/agent-builder/components/VariableTriggerArea.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { VariablePicker } from '../../variable-picker-v3';\nimport { PickerType } from '../../variable-picker-v3/model';\nimport type {\n\tVariableListInterfaceV3,\n\tVariableV3,\n} from '../../variable-picker-v3/model';\nimport { variableTokenName } from '../utils/mentionSerialization';\n\n/** The persisted form of a picked variable (`{{variable:<name>}}`). */\nexport const variableToken = (variable: VariableV3): string =>\n\t`{{variable:${variableTokenName(variable.actualValue)}}}`;\n\n/**\n * Boundary test for the `@` trigger: an `@` typed at the start of the field or\n * after a separator opens the picker. The separator set covers URL and JSON\n * delimiters too (`https://@`, `Bearer=@`, `\"@`, `[@`) — an email address's `@`\n * always follows a letter / digit / dot, so `john@acme.com` still types\n * through untouched. Returns the caret index for input / textarea targets\n * (where the caller can splice the token in), null for contenteditable ones.\n */\nconst BOUNDARY = /[\\s,;:/?&=(){}[\\]\"'<>]/;\n\nconst triggerContext = (\n\ttarget: EventTarget | null,\n): { ok: boolean; caret: number | null; textBefore: string } => {\n\tif (\n\t\ttarget instanceof HTMLInputElement ||\n\t\ttarget instanceof HTMLTextAreaElement\n\t) {\n\t\tconst caret = target.selectionStart ?? target.value.length;\n\t\tconst prev = caret === 0 ? ' ' : target.value[caret - 1] ?? ' ';\n\t\treturn {\n\t\t\tok: BOUNDARY.test(prev),\n\t\t\tcaret,\n\t\t\ttextBefore: target.value.slice(0, caret),\n\t\t};\n\t}\n\t// Rich editor (ProseMirror contenteditable): read the character before the\n\t// selection. `textBefore` is only the current text-node fragment (fine for\n\t// the token transforms, which just look at nearby characters).\n\tconst sel = window.getSelection();\n\tconst text = sel?.anchorNode?.textContent ?? '';\n\tconst offset = sel?.anchorOffset ?? 0;\n\tconst prev = offset === 0 ? ' ' : text[offset - 1] ?? ' ';\n\treturn {\n\t\tok: BOUNDARY.test(prev),\n\t\tcaret: null,\n\t\ttextBefore: text.slice(0, offset),\n\t};\n};\n\ninterface VariableTriggerAreaProps {\n\t/** Variable catalog. Absent / empty → the wrapper is inert (children only). */\n\tvariablesData?: VariableListInterfaceV3[];\n\t/**\n\t * Insert `token` into the wrapped field. `caret` is the character index the\n\t * `@` was typed at (input / textarea targets — splice the token in there);\n\t * null for rich-editor targets (insert at the editor's own cursor).\n\t */\n\tonInsert: (token: string, caret: number | null) => void;\n\t/**\n\t * Rewrite the token before it's handed to `onInsert` — e.g. the Rest API\n\t * JSON editors wrap it in quotes. `textBefore` is the text preceding the\n\t * `@` (for input targets the whole value up to the caret; for rich-editor\n\t * targets just the current text-node fragment).\n\t */\n\ttransformToken?: (token: string, ctx: { textBefore: string }) => string;\n\tchildren: React.ReactNode;\n}\n\n/**\n * Wraps any plain field (input / textarea / chips entry / BikEditor) and opens\n * the shared {@link VariablePicker} as a floating panel when `@` is typed at a\n * word boundary. The `@` keystroke itself is swallowed (never reaches the\n * field); picking a variable calls `onInsert` with the `{{variable:<name>}}`\n * token, and Escape / click-outside / the panel's ✕ just closes the panel.\n *\n * Purely presentational wrapper — it renders a `position: relative` block, so\n * the wrapped field must be happy inside a plain block container.\n */\nexport const VariableTriggerArea: React.FC<VariableTriggerAreaProps> = ({\n\tvariablesData,\n\tonInsert,\n\ttransformToken,\n\tchildren,\n}) => {\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\t// Non-null while the panel is open: where to put the token when picked, and\n\t// which way the panel flips to stay on screen (above when there's no room\n\t// below, right-aligned when the field sits too close to the right edge —\n\t// e.g. header-value inputs in the Rest API drawer).\n\tconst [trigger, setTrigger] = useState<{\n\t\tcaret: number | null;\n\t\ttextBefore: string;\n\t\tabove: boolean;\n\t\talignRight: boolean;\n\t} | null>(null);\n\n\tconst enabled = (variablesData?.length ?? 0) > 0;\n\n\tconst onKeyDownCapture = useCallback(\n\t\t(e: React.KeyboardEvent) => {\n\t\t\tif (!enabled || e.key !== '@') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst ctx = triggerContext(e.target);\n\t\t\tif (!ctx.ok) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Swallow the `@` so the field's value stays untouched while picking.\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tconst rect = containerRef.current?.getBoundingClientRect();\n\t\t\tconst above = !!rect && window.innerHeight - rect.bottom < 340;\n\t\t\t// Panel is ~344px wide, anchored to the field's left edge — flip to the\n\t\t\t// right edge when that would spill past the viewport (avoids the drawer\n\t\t\t// growing a horizontal scrollbar).\n\t\t\tconst alignRight = !!rect && window.innerWidth - rect.left < 360;\n\t\t\tsetTrigger({\n\t\t\t\tcaret: ctx.caret,\n\t\t\t\ttextBefore: ctx.textBefore,\n\t\t\t\tabove,\n\t\t\t\talignRight,\n\t\t\t});\n\t\t},\n\t\t[enabled],\n\t);\n\n\t// Escape / click-outside dismiss, active only while open.\n\tuseEffect(() => {\n\t\tif (!trigger) {\n\t\t\treturn;\n\t\t}\n\t\tconst onKey = (e: KeyboardEvent) => {\n\t\t\tif (e.key === 'Escape') {\n\t\t\t\te.stopPropagation();\n\t\t\t\tsetTrigger(null);\n\t\t\t}\n\t\t};\n\t\tconst onDown = (e: MouseEvent) => {\n\t\t\tif (!containerRef.current?.contains(e.target as Node)) {\n\t\t\t\tsetTrigger(null);\n\t\t\t}\n\t\t};\n\t\t// Capture phase so an Escape meant for the panel never also closes the\n\t\t// drawer underneath.\n\t\tdocument.addEventListener('keydown', onKey, true);\n\t\tdocument.addEventListener('mousedown', onDown);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('keydown', onKey, true);\n\t\t\tdocument.removeEventListener('mousedown', onDown);\n\t\t};\n\t}, [trigger]);\n\n\treturn (\n\t\t<TriggerWrap ref={containerRef} onKeyDownCapture={onKeyDownCapture}>\n\t\t\t{children}\n\t\t\t{trigger && (\n\t\t\t\t<FloaterBox\n\t\t\t\t\t$above={trigger.above}\n\t\t\t\t\t$right={trigger.alignRight}\n\t\t\t\t\tdata-test=\"variable-trigger-panel\"\n\t\t\t\t>\n\t\t\t\t\t<VariablePicker\n\t\t\t\t\t\ttype={PickerType.FLOATER}\n\t\t\t\t\t\tdata={variablesData ?? []}\n\t\t\t\t\t\tshowRecommendedBar={false}\n\t\t\t\t\t\tonClose={() => setTrigger(null)}\n\t\t\t\t\t\tonSelect={(variable: VariableV3) => {\n\t\t\t\t\t\t\tsetTrigger(null);\n\t\t\t\t\t\t\tconst raw = variableToken(variable);\n\t\t\t\t\t\t\tconst token = transformToken\n\t\t\t\t\t\t\t\t? transformToken(raw, { textBefore: trigger.textBefore })\n\t\t\t\t\t\t\t\t: raw;\n\t\t\t\t\t\t\tonInsert(token, trigger.caret);\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</FloaterBox>\n\t\t\t)}\n\t\t</TriggerWrap>\n\t);\n};\n\nconst TriggerWrap = styled.div`\n\tposition: relative;\n`;\n\n// Floats under (or over) the wrapped field; VariablePicker brings its own card\n// styling. High z-index: these fields live inside side-modal drawers.\nconst FloaterBox = styled.div<{ $above: boolean; $right: boolean }>`\n\tposition: absolute;\n\tz-index: 1000;\n\t${(p) => (p.$right ? 'right: 0;' : 'left: 0;')}\n\t${(p) => (p.$above ? 'bottom: calc(100% + 4px);' : 'top: calc(100% + 4px);')}\n`;\n"],"names":["variableToken","variable","variableTokenName","BOUNDARY","triggerContext","target","caret","prev","sel","text","offset","VariableTriggerArea","variablesData","onInsert","transformToken","children","containerRef","useRef","trigger","setTrigger","useState","enabled","onKeyDownCapture","useCallback","e","ctx","rect","above","alignRight","useEffect","onKey","onDown","jsxs","TriggerWrap","jsx","FloaterBox","VariablePicker","PickerType","raw","token","styled","p"],"mappings":"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"}
|
|
@@ -22,6 +22,15 @@ interface RestApiToolPanelProps {
|
|
|
22
22
|
*/
|
|
23
23
|
variablesData?: VariableListInterfaceV3[];
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Keep the Request / Response bodies valid JSON: wrap the picked token in
|
|
27
|
+
* quotes (`"email": "{{variable:customer.email}}"`) — unless the `@` was typed
|
|
28
|
+
* inside a string literal already (odd number of unescaped `"` before it, e.g.
|
|
29
|
+
* `"Bearer @`), where the bare token interpolates into the existing string.
|
|
30
|
+
*/
|
|
31
|
+
export declare const jsonQuoteToken: (token: string, ctx: {
|
|
32
|
+
textBefore: string;
|
|
33
|
+
}) => string;
|
|
25
34
|
/**
|
|
26
35
|
* Right-side drawer to configure a "Rest API" tool: the endpoint the agent can
|
|
27
36
|
* call, plus a JSON request-body template and a sample response. Mount it fresh
|
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { useState as
|
|
5
|
-
import
|
|
1
|
+
import { jsxs as d, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import K from "../../../assets/icons/delete.svg.js";
|
|
3
|
+
import Q from "../../../assets/icons/plus.svg.js";
|
|
4
|
+
import { useState as l, useRef as D } from "react";
|
|
5
|
+
import b from "styled-components";
|
|
6
6
|
import { TitleSmall as u } from "../../TypographyStyle.js";
|
|
7
|
-
import { COLORS as
|
|
7
|
+
import { COLORS as i } from "../../../constants/Theme.js";
|
|
8
8
|
import { FieldBlock as p } from "../AgentBuilder.styled.js";
|
|
9
|
-
import { AGENT_CHAR_LIMITS as
|
|
10
|
-
import { DRAWER_BODY_STYLE as
|
|
11
|
-
import { ToolInstructionsField as
|
|
9
|
+
import { AGENT_CHAR_LIMITS as X } from "../constants/charLimits.js";
|
|
10
|
+
import { DRAWER_BODY_STYLE as Z, DRAWER_HEADER_STYLE as ee, DrawerHeaderText as te } from "./DrawerHeaderText.js";
|
|
11
|
+
import { ToolInstructionsField as re } from "./ToolInstructionsField.js";
|
|
12
12
|
import { VariableTriggerArea as h } from "./VariableTriggerArea.js";
|
|
13
|
-
import { SideModal as
|
|
13
|
+
import { SideModal as oe } from "../../side-modal/SideModal.js";
|
|
14
14
|
import { Input as f } from "../../input/Input.js";
|
|
15
|
-
import { Dropdown as
|
|
16
|
-
import { unwrapDropdownValue as
|
|
17
|
-
import { Button as
|
|
18
|
-
import { BikEditor as
|
|
19
|
-
const
|
|
20
|
-
label:
|
|
21
|
-
value:
|
|
22
|
-
})),
|
|
23
|
-
onClose:
|
|
24
|
-
onSave:
|
|
25
|
-
initial:
|
|
26
|
-
onImprove:
|
|
27
|
-
charLimits:
|
|
28
|
-
zIndex:
|
|
29
|
-
existingNames:
|
|
15
|
+
import { Dropdown as ne } from "../../dropdown/Dropdown.js";
|
|
16
|
+
import { unwrapDropdownValue as ae } from "../../dropdown/utils.js";
|
|
17
|
+
import { Button as se } from "../../button/Button.js";
|
|
18
|
+
import { BikEditor as q } from "../../../editor/BikEditor.js";
|
|
19
|
+
const le = ["GET", "POST", "PUT", "PATCH", "DELETE"], ie = le.map((s) => ({
|
|
20
|
+
label: s,
|
|
21
|
+
value: s
|
|
22
|
+
})), M = (s, y) => (y.textBefore.match(new RegExp('(?<!\\\\)"', "g"))?.length ?? 0) % 2 === 1 ? s : `"${s}"`, Be = ({
|
|
23
|
+
onClose: s,
|
|
24
|
+
onSave: y,
|
|
25
|
+
initial: n,
|
|
26
|
+
onImprove: N,
|
|
27
|
+
charLimits: I = X,
|
|
28
|
+
zIndex: j,
|
|
29
|
+
existingNames: z = [],
|
|
30
30
|
variablesData: c
|
|
31
31
|
}) => {
|
|
32
|
-
const [
|
|
33
|
-
|
|
34
|
-
), [A,
|
|
35
|
-
|
|
36
|
-
), [
|
|
37
|
-
|
|
38
|
-
), [
|
|
39
|
-
(o) => o.map((
|
|
40
|
-
),
|
|
41
|
-
(e) => e.trim().toLowerCase() ===
|
|
42
|
-
),
|
|
43
|
-
return /* @__PURE__ */
|
|
44
|
-
|
|
32
|
+
const [x, F] = l(n?.name ?? ""), E = D(null), H = D(null), [w, G] = l(n?.instructions ?? ""), [T, k] = l(n?.url ?? "https://"), [g, J] = l(
|
|
33
|
+
n?.method ?? "POST"
|
|
34
|
+
), [A, v] = l(
|
|
35
|
+
n?.headers ?? [{ key: "", value: "" }]
|
|
36
|
+
), [B, U] = l(n?.requestBody ?? ""), [P, W] = l(
|
|
37
|
+
n?.responseSample ?? ""
|
|
38
|
+
), [L, O] = l(!1), S = (e, r) => v(
|
|
39
|
+
(o) => o.map((a, m) => m === e ? { ...a, ...r } : a)
|
|
40
|
+
), Y = () => v((e) => [...e, { key: "", value: "" }]), V = (e) => v((r) => r.filter((o, a) => a !== e)), C = x.trim(), R = C.length > 0 && z.some(
|
|
41
|
+
(e) => e.trim().toLowerCase() === C.toLowerCase()
|
|
42
|
+
), $ = C.length > 0 && T.trim().length > 0 && !R;
|
|
43
|
+
return /* @__PURE__ */ d(
|
|
44
|
+
oe,
|
|
45
45
|
{
|
|
46
46
|
header: "Rest API",
|
|
47
47
|
closeOnEscapeKey: !1,
|
|
48
|
-
zIndex:
|
|
48
|
+
zIndex: j,
|
|
49
49
|
headerCustomComponent: /* @__PURE__ */ t(
|
|
50
|
-
|
|
50
|
+
te,
|
|
51
51
|
{
|
|
52
52
|
title: "Rest API",
|
|
53
53
|
subtitle: "Connect to any API endpoint. Define the request and a sample response for the agent to reference."
|
|
54
54
|
}
|
|
55
55
|
),
|
|
56
56
|
width: "431px",
|
|
57
|
-
headerStyle:
|
|
58
|
-
bodyStyle:
|
|
59
|
-
onClose:
|
|
57
|
+
headerStyle: ee,
|
|
58
|
+
bodyStyle: Z,
|
|
59
|
+
onClose: s,
|
|
60
60
|
saveButtonProps: {
|
|
61
61
|
"data-test": "restapi-save",
|
|
62
62
|
buttonText: "Save",
|
|
63
63
|
buttonType: "primary",
|
|
64
64
|
size: "small",
|
|
65
|
-
disabled:
|
|
66
|
-
isLoading:
|
|
65
|
+
disabled: !$,
|
|
66
|
+
isLoading: L,
|
|
67
67
|
onClick: async () => {
|
|
68
|
-
if (
|
|
68
|
+
if (!$ || L)
|
|
69
69
|
return;
|
|
70
70
|
const e = {
|
|
71
|
-
id:
|
|
72
|
-
name:
|
|
73
|
-
instructions:
|
|
74
|
-
url:
|
|
75
|
-
method:
|
|
71
|
+
id: n?.id ?? `restapi_${Date.now().toString(36)}`,
|
|
72
|
+
name: x.trim(),
|
|
73
|
+
instructions: w,
|
|
74
|
+
url: T.trim(),
|
|
75
|
+
method: g,
|
|
76
76
|
// Drop fully-empty header rows.
|
|
77
77
|
headers: A.filter((o) => o.key.trim() || o.value.trim()),
|
|
78
|
-
requestBody:
|
|
78
|
+
requestBody: B,
|
|
79
79
|
responseSample: P
|
|
80
|
-
}, r =
|
|
80
|
+
}, r = y(e);
|
|
81
81
|
if (r && typeof r.then == "function") {
|
|
82
|
-
|
|
82
|
+
O(!0);
|
|
83
83
|
try {
|
|
84
84
|
await r;
|
|
85
85
|
} finally {
|
|
86
|
-
|
|
86
|
+
O(!1);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
}
|
|
@@ -93,7 +93,7 @@ const se = ["GET", "POST", "PUT", "PATCH", "DELETE"], le = se.map((d) => ({
|
|
|
93
93
|
buttonText: "Cancel",
|
|
94
94
|
buttonType: "tertiaryGray",
|
|
95
95
|
size: "small",
|
|
96
|
-
onClick:
|
|
96
|
+
onClick: s
|
|
97
97
|
},
|
|
98
98
|
children: [
|
|
99
99
|
/* @__PURE__ */ t(
|
|
@@ -104,23 +104,23 @@ const se = ["GET", "POST", "PUT", "PATCH", "DELETE"], le = se.map((d) => ({
|
|
|
104
104
|
labelText: "Name",
|
|
105
105
|
labelTextBold: !0,
|
|
106
106
|
placeholder: "Enter action name",
|
|
107
|
-
value:
|
|
108
|
-
maxCharLimit:
|
|
109
|
-
state:
|
|
110
|
-
errorMessage:
|
|
111
|
-
onChangeText:
|
|
107
|
+
value: x,
|
|
108
|
+
maxCharLimit: I.name,
|
|
109
|
+
state: R ? "invalid" : void 0,
|
|
110
|
+
errorMessage: R ? "A tool with this name already exists" : void 0,
|
|
111
|
+
onChangeText: F
|
|
112
112
|
}
|
|
113
113
|
),
|
|
114
114
|
/* @__PURE__ */ t(
|
|
115
|
-
|
|
115
|
+
re,
|
|
116
116
|
{
|
|
117
117
|
"data-test": "restapi-instructions",
|
|
118
118
|
label: "Instructions",
|
|
119
|
-
value:
|
|
120
|
-
onChange:
|
|
121
|
-
maxLength:
|
|
119
|
+
value: w,
|
|
120
|
+
onChange: G,
|
|
121
|
+
maxLength: I.instructions,
|
|
122
122
|
placeholder: "Describe how should the LLM generate the rest API",
|
|
123
|
-
onImprove:
|
|
123
|
+
onImprove: N,
|
|
124
124
|
variablesData: c
|
|
125
125
|
}
|
|
126
126
|
),
|
|
@@ -128,9 +128,9 @@ const se = ["GET", "POST", "PUT", "PATCH", "DELETE"], le = se.map((d) => ({
|
|
|
128
128
|
h,
|
|
129
129
|
{
|
|
130
130
|
variablesData: c,
|
|
131
|
-
onInsert: (e, r) =>
|
|
132
|
-
const
|
|
133
|
-
return `${o.slice(0,
|
|
131
|
+
onInsert: (e, r) => k((o) => {
|
|
132
|
+
const a = r ?? o.length;
|
|
133
|
+
return `${o.slice(0, a)}${e}${o.slice(a)}`;
|
|
134
134
|
}),
|
|
135
135
|
children: /* @__PURE__ */ t(
|
|
136
136
|
f,
|
|
@@ -141,35 +141,35 @@ const se = ["GET", "POST", "PUT", "PATCH", "DELETE"], le = se.map((d) => ({
|
|
|
141
141
|
labelTextBold: !0,
|
|
142
142
|
placeholder: "https://",
|
|
143
143
|
type: "url",
|
|
144
|
-
value:
|
|
145
|
-
onChangeText:
|
|
144
|
+
value: T,
|
|
145
|
+
onChangeText: k
|
|
146
146
|
}
|
|
147
147
|
)
|
|
148
148
|
}
|
|
149
149
|
) }),
|
|
150
|
-
/* @__PURE__ */
|
|
151
|
-
/* @__PURE__ */ t(u, { color:
|
|
150
|
+
/* @__PURE__ */ d(p, { children: [
|
|
151
|
+
/* @__PURE__ */ t(u, { color: i.content.primary, children: "HTTP method" }),
|
|
152
152
|
/* @__PURE__ */ t(
|
|
153
|
-
|
|
153
|
+
ne,
|
|
154
154
|
{
|
|
155
155
|
"data-test": "restapi-method",
|
|
156
156
|
size: "small",
|
|
157
157
|
width: "100%",
|
|
158
158
|
dropdownWidth: "399px",
|
|
159
|
-
options:
|
|
160
|
-
defaultOptions: [{ label:
|
|
159
|
+
options: ie,
|
|
160
|
+
defaultOptions: [{ label: g, value: g }],
|
|
161
161
|
onSelect: (e) => {
|
|
162
|
-
const r =
|
|
163
|
-
r &&
|
|
162
|
+
const r = ae(e);
|
|
163
|
+
r && J(r);
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
)
|
|
167
167
|
] }),
|
|
168
|
-
/* @__PURE__ */
|
|
169
|
-
/* @__PURE__ */ t(u, { color:
|
|
168
|
+
/* @__PURE__ */ d(p, { children: [
|
|
169
|
+
/* @__PURE__ */ t(u, { color: i.content.primary, children: "Headers" }),
|
|
170
170
|
A.map((e, r) => (
|
|
171
171
|
// eslint-disable-next-line react/no-array-index-key
|
|
172
|
-
/* @__PURE__ */
|
|
172
|
+
/* @__PURE__ */ d(de, { "data-test": `restapi-header-${r}`, children: [
|
|
173
173
|
/* @__PURE__ */ t(
|
|
174
174
|
f,
|
|
175
175
|
{
|
|
@@ -177,16 +177,16 @@ const se = ["GET", "POST", "PUT", "PATCH", "DELETE"], le = se.map((d) => ({
|
|
|
177
177
|
hideInputHeader: !0,
|
|
178
178
|
placeholder: "Enter name",
|
|
179
179
|
value: e.key,
|
|
180
|
-
onChangeText: (o) =>
|
|
180
|
+
onChangeText: (o) => S(r, { key: o })
|
|
181
181
|
}
|
|
182
182
|
),
|
|
183
183
|
/* @__PURE__ */ t(
|
|
184
184
|
h,
|
|
185
185
|
{
|
|
186
186
|
variablesData: c,
|
|
187
|
-
onInsert: (o,
|
|
188
|
-
const m =
|
|
189
|
-
|
|
187
|
+
onInsert: (o, a) => {
|
|
188
|
+
const m = a ?? e.value.length;
|
|
189
|
+
S(r, {
|
|
190
190
|
value: `${e.value.slice(0, m)}${o}${e.value.slice(m)}`
|
|
191
191
|
});
|
|
192
192
|
},
|
|
@@ -197,58 +197,59 @@ const se = ["GET", "POST", "PUT", "PATCH", "DELETE"], le = se.map((d) => ({
|
|
|
197
197
|
hideInputHeader: !0,
|
|
198
198
|
placeholder: "Enter value",
|
|
199
199
|
value: e.value,
|
|
200
|
-
onChangeText: (o) =>
|
|
200
|
+
onChangeText: (o) => S(r, { value: o })
|
|
201
201
|
}
|
|
202
202
|
)
|
|
203
203
|
}
|
|
204
204
|
),
|
|
205
205
|
/* @__PURE__ */ t(
|
|
206
|
-
|
|
206
|
+
pe,
|
|
207
207
|
{
|
|
208
208
|
type: "button",
|
|
209
209
|
"aria-label": "Remove header",
|
|
210
210
|
"data-test": `restapi-header-remove-${r}`,
|
|
211
|
-
onClick: () =>
|
|
211
|
+
onClick: () => V(r),
|
|
212
212
|
children: /* @__PURE__ */ t(
|
|
213
|
-
|
|
213
|
+
K,
|
|
214
214
|
{
|
|
215
215
|
width: 16,
|
|
216
216
|
height: 16,
|
|
217
|
-
color:
|
|
217
|
+
color: i.content.secondary
|
|
218
218
|
}
|
|
219
219
|
)
|
|
220
220
|
}
|
|
221
221
|
)
|
|
222
222
|
] }, r)
|
|
223
223
|
)),
|
|
224
|
-
/* @__PURE__ */ t(
|
|
225
|
-
|
|
224
|
+
/* @__PURE__ */ t(ce, { children: /* @__PURE__ */ t(
|
|
225
|
+
se,
|
|
226
226
|
{
|
|
227
227
|
"data-test": "restapi-add-header",
|
|
228
228
|
buttonType: "dashRegular",
|
|
229
229
|
size: "small",
|
|
230
|
-
LeadingIcon:
|
|
230
|
+
LeadingIcon: Q,
|
|
231
231
|
buttonText: "Add header",
|
|
232
|
-
onClick:
|
|
232
|
+
onClick: Y
|
|
233
233
|
}
|
|
234
234
|
) })
|
|
235
235
|
] }),
|
|
236
|
-
/* @__PURE__ */
|
|
237
|
-
/* @__PURE__ */ t(u, { color:
|
|
236
|
+
/* @__PURE__ */ d(p, { children: [
|
|
237
|
+
/* @__PURE__ */ t(u, { color: i.content.primary, children: "Request " }),
|
|
238
238
|
/* @__PURE__ */ t(
|
|
239
239
|
h,
|
|
240
240
|
{
|
|
241
241
|
variablesData: c,
|
|
242
|
-
|
|
242
|
+
transformToken: M,
|
|
243
|
+
onInsert: (e) => E.current?.insertInlineContent(e),
|
|
243
244
|
children: /* @__PURE__ */ t(
|
|
244
|
-
|
|
245
|
+
q,
|
|
245
246
|
{
|
|
246
|
-
ref:
|
|
247
|
+
ref: E,
|
|
247
248
|
features: { jsonMode: !0 },
|
|
248
|
-
initialContent:
|
|
249
|
-
style:
|
|
249
|
+
initialContent: B,
|
|
250
|
+
style: _,
|
|
250
251
|
placeholder: "Type or paste JSON here",
|
|
251
|
-
onChange: (e) =>
|
|
252
|
+
onChange: (e) => U(e.text),
|
|
252
253
|
minHeight: "120px",
|
|
253
254
|
maxHeight: "240px"
|
|
254
255
|
}
|
|
@@ -256,22 +257,23 @@ const se = ["GET", "POST", "PUT", "PATCH", "DELETE"], le = se.map((d) => ({
|
|
|
256
257
|
}
|
|
257
258
|
)
|
|
258
259
|
] }),
|
|
259
|
-
/* @__PURE__ */
|
|
260
|
-
/* @__PURE__ */ t(u, { color:
|
|
260
|
+
/* @__PURE__ */ d(p, { children: [
|
|
261
|
+
/* @__PURE__ */ t(u, { color: i.content.primary, children: "Response " }),
|
|
261
262
|
/* @__PURE__ */ t(
|
|
262
263
|
h,
|
|
263
264
|
{
|
|
264
265
|
variablesData: c,
|
|
265
|
-
|
|
266
|
+
transformToken: M,
|
|
267
|
+
onInsert: (e) => H.current?.insertInlineContent(e),
|
|
266
268
|
children: /* @__PURE__ */ t(
|
|
267
|
-
|
|
269
|
+
q,
|
|
268
270
|
{
|
|
269
|
-
ref:
|
|
271
|
+
ref: H,
|
|
270
272
|
features: { jsonMode: !0 },
|
|
271
|
-
style:
|
|
273
|
+
style: _,
|
|
272
274
|
initialContent: P,
|
|
273
275
|
placeholder: "Type or paste JSON here",
|
|
274
|
-
onChange: (e) =>
|
|
276
|
+
onChange: (e) => W(e.text),
|
|
275
277
|
minHeight: "120px",
|
|
276
278
|
maxHeight: "240px"
|
|
277
279
|
}
|
|
@@ -282,33 +284,34 @@ const se = ["GET", "POST", "PUT", "PATCH", "DELETE"], le = se.map((d) => ({
|
|
|
282
284
|
]
|
|
283
285
|
}
|
|
284
286
|
);
|
|
285
|
-
},
|
|
287
|
+
}, de = b.div`
|
|
286
288
|
display: flex;
|
|
287
289
|
align-items: center;
|
|
288
290
|
gap: 8px;
|
|
289
|
-
`,
|
|
291
|
+
`, ce = b.div`
|
|
290
292
|
display: flex;
|
|
291
|
-
`,
|
|
293
|
+
`, pe = b.button`
|
|
292
294
|
display: inline-flex;
|
|
293
295
|
align-items: center;
|
|
294
296
|
justify-content: center;
|
|
295
297
|
flex-shrink: 0;
|
|
296
298
|
width: 32px;
|
|
297
299
|
height: 32px;
|
|
298
|
-
border: 1px solid ${
|
|
300
|
+
border: 1px solid ${i.stroke.primary};
|
|
299
301
|
border-radius: 4px;
|
|
300
|
-
background: ${
|
|
302
|
+
background: ${i.surface.standard};
|
|
301
303
|
cursor: pointer;
|
|
302
304
|
|
|
303
305
|
&:hover {
|
|
304
|
-
border-color: ${
|
|
306
|
+
border-color: ${i.content.secondary};
|
|
305
307
|
}
|
|
306
|
-
`,
|
|
308
|
+
`, _ = {
|
|
307
309
|
borderRadius: "4px",
|
|
308
310
|
overflow: "hidden"
|
|
309
311
|
};
|
|
310
312
|
export {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
+
_ as JsonFieldBox,
|
|
314
|
+
Be as RestApiToolPanel,
|
|
315
|
+
M as jsonQuoteToken
|
|
313
316
|
};
|
|
314
317
|
//# sourceMappingURL=RestApiToolPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RestApiToolPanel.js","sources":["../../../../../src/components/agent-builder/components/RestApiToolPanel.tsx"],"sourcesContent":["import DeleteIcon from '@src/assets/icons/delete.svg';\nimport PlusIcon from '@src/assets/icons/plus.svg';\nimport { BikEditor, BikEditorRef } from '@src/editor';\nimport React, { useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { Button } from '@src/components/button';\nimport { Dropdown, unwrapDropdownValue } from '@src/components/dropdown';\nimport { SingleOption } from '@src/components/dropdown/type';\nimport { Input } from '@src/components/input';\nimport { SideModal } from '@src/components/side-modal';\nimport { TitleSmall } from '@src/components/TypographyStyle';\nimport { COLORS } from '@src/constants/Theme';\nimport type { VariableListInterfaceV3 } from '../../variable-picker-v3/model';\nimport {\n\tRestApiHeader,\n\tRestApiMethod,\n\tRestApiToolConfig,\n} from '../AgentBuilder.model';\nimport { FieldBlock } from '../AgentBuilder.styled';\nimport type { AgentCharLimits } from '../constants/charLimits';\nimport { AGENT_CHAR_LIMITS } from '../constants/charLimits';\nimport {\n\tDRAWER_BODY_STYLE,\n\tDRAWER_HEADER_STYLE,\n\tDrawerHeaderText,\n} from './DrawerHeaderText';\nimport { ToolInstructionsField } from './ToolInstructionsField';\nimport { VariableTriggerArea } from './VariableTriggerArea';\n\ninterface RestApiToolPanelProps {\n\tonClose: () => void;\n\t/** Persist the config. A pending promise shows the Save loader. */\n\tonSave: (config: RestApiToolConfig) => void | Promise<void>;\n\t/** Seed values when editing an existing tool. */\n\tinitial?: RestApiToolConfig;\n\t/** Optional \"Improve with AI\" for the instructions field. Omit to hide it. */\n\tonImprove?: (text: string) => Promise<string>;\n\tcharLimits?: AgentCharLimits;\n\t/** SideModal stacking order — raise it when opened over another drawer. */\n\tzIndex?: number;\n\t/** Names of the OTHER tools — a new tool can't reuse one of these. */\n\texistingNames?: string[];\n\t/**\n\t * Variable catalog for the `@` trigger. When non-empty, `@` opens the\n\t * variable picker directly in Instructions / Request URL / header values /\n\t * Request / Response. Absent → the drawer behaves exactly as before.\n\t */\n\tvariablesData?: VariableListInterfaceV3[];\n}\n\nconst METHODS: RestApiMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];\nconst METHOD_OPTIONS: SingleOption[] = METHODS.map((m) => ({\n\tlabel: m,\n\tvalue: m,\n}));\n\n/**\n * Right-side drawer to configure a \"Rest API\" tool: the endpoint the agent can\n * call, plus a JSON request-body template and a sample response. Mount it fresh\n * per open (key it) so `initial` seeds the state. Built on the shared `SideModal`\n * shell and the BikEditor JSON body mode for the Request / Response editors.\n */\nexport const RestApiToolPanel: React.FC<RestApiToolPanelProps> = ({\n\tonClose,\n\tonSave,\n\tinitial,\n\tonImprove,\n\tcharLimits = AGENT_CHAR_LIMITS,\n\tzIndex,\n\texistingNames = [],\n\tvariablesData,\n}) => {\n\tconst [name, setName] = useState(initial?.name ?? '');\n\t// `@`-picked variables insert into the JSON editors at their own cursor.\n\tconst requestEditorRef = useRef<BikEditorRef>(null);\n\tconst responseEditorRef = useRef<BikEditorRef>(null);\n\tconst [instructions, setInstructions] = useState(initial?.instructions ?? '');\n\t// New tools start with the scheme pre-filled so the user only types the host.\n\tconst [url, setUrl] = useState(initial?.url ?? 'https://');\n\tconst [method, setMethod] = useState<RestApiMethod>(\n\t\tinitial?.method ?? 'POST',\n\t);\n\tconst [headers, setHeaders] = useState<RestApiHeader[]>(\n\t\tinitial?.headers ?? [{ key: '', value: '' }],\n\t);\n\tconst [requestBody, setRequestBody] = useState(initial?.requestBody ?? '');\n\tconst [responseSample, setResponseSample] = useState(\n\t\tinitial?.responseSample ?? '',\n\t);\n\tconst [saving, setSaving] = useState(false);\n\n\tconst patchHeader = (i: number, patch: Partial<RestApiHeader>) =>\n\t\tsetHeaders((prev) =>\n\t\t\tprev.map((h, idx) => (idx === i ? { ...h, ...patch } : h)),\n\t\t);\n\tconst addHeader = () =>\n\t\tsetHeaders((prev) => [...prev, { key: '', value: '' }]);\n\tconst removeHeader = (i: number) =>\n\t\tsetHeaders((prev) => prev.filter((_, idx) => idx !== i));\n\n\tconst nameTrimmed = name.trim();\n\t// Case-insensitive: two tools can't share a name (the LLM references them by it).\n\tconst isDuplicateName =\n\t\tnameTrimmed.length > 0 &&\n\t\texistingNames.some(\n\t\t\t(n) => n.trim().toLowerCase() === nameTrimmed.toLowerCase(),\n\t\t);\n\tconst canSave =\n\t\tnameTrimmed.length > 0 && url.trim().length > 0 && !isDuplicateName;\n\n\tconst handleSave = async () => {\n\t\tif (!canSave || saving) {\n\t\t\treturn;\n\t\t}\n\t\tconst config: RestApiToolConfig = {\n\t\t\tid: initial?.id ?? `restapi_${Date.now().toString(36)}`,\n\t\t\tname: name.trim(),\n\t\t\tinstructions,\n\t\t\turl: url.trim(),\n\t\t\tmethod,\n\t\t\t// Drop fully-empty header rows.\n\t\t\theaders: headers.filter((h) => h.key.trim() || h.value.trim()),\n\t\t\trequestBody,\n\t\t\tresponseSample,\n\t\t};\n\t\tconst result = onSave(config);\n\t\tif (result && typeof (result as Promise<void>).then === 'function') {\n\t\t\tsetSaving(true);\n\t\t\ttry {\n\t\t\t\tawait result;\n\t\t\t} finally {\n\t\t\t\tsetSaving(false);\n\t\t\t}\n\t\t}\n\t};\n\n\treturn (\n\t\t<SideModal\n\t\t\theader=\"Rest API\"\n\t\t\tcloseOnEscapeKey={false}\n\t\t\tzIndex={zIndex}\n\t\t\theaderCustomComponent={\n\t\t\t\t<DrawerHeaderText\n\t\t\t\t\ttitle=\"Rest API\"\n\t\t\t\t\tsubtitle=\"Connect to any API endpoint. Define the request and a sample response for the agent to reference.\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\twidth=\"431px\"\n\t\t\theaderStyle={DRAWER_HEADER_STYLE}\n\t\t\tbodyStyle={DRAWER_BODY_STYLE}\n\t\t\tonClose={onClose}\n\t\t\tsaveButtonProps={{\n\t\t\t\t'data-test': 'restapi-save',\n\t\t\t\tbuttonText: 'Save',\n\t\t\t\tbuttonType: 'primary',\n\t\t\t\tsize: 'small',\n\t\t\t\tdisabled: !canSave,\n\t\t\t\tisLoading: saving,\n\t\t\t\tonClick: handleSave,\n\t\t\t}}\n\t\t\tcancelButtonProps={{\n\t\t\t\t'data-test': 'restapi-cancel',\n\t\t\t\tbuttonText: 'Cancel',\n\t\t\t\tbuttonType: 'tertiaryGray',\n\t\t\t\tsize: 'small',\n\t\t\t\tonClick: onClose,\n\t\t\t}}\n\t\t>\n\t\t\t<Input\n\t\t\t\tdata-test=\"restapi-name\"\n\t\t\t\tvariant=\"small\"\n\t\t\t\tlabelText=\"Name\"\n\t\t\t\tlabelTextBold\n\t\t\t\tplaceholder=\"Enter action name\"\n\t\t\t\tvalue={name}\n\t\t\t\tmaxCharLimit={charLimits.name}\n\t\t\t\tstate={isDuplicateName ? 'invalid' : undefined}\n\t\t\t\terrorMessage={\n\t\t\t\t\tisDuplicateName ? 'A tool with this name already exists' : undefined\n\t\t\t\t}\n\t\t\t\tonChangeText={setName}\n\t\t\t/>\n\n\t\t\t<ToolInstructionsField\n\t\t\t\tdata-test=\"restapi-instructions\"\n\t\t\t\tlabel=\"Instructions\"\n\t\t\t\tvalue={instructions}\n\t\t\t\tonChange={setInstructions}\n\t\t\t\tmaxLength={charLimits.instructions}\n\t\t\t\tplaceholder=\"Describe how should the LLM generate the rest API\"\n\t\t\t\tonImprove={onImprove}\n\t\t\t\tvariablesData={variablesData}\n\t\t\t/>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\tonInsert={(token, caret) =>\n\t\t\t\t\t\tsetUrl((u) => {\n\t\t\t\t\t\t\tconst at = caret ?? u.length;\n\t\t\t\t\t\t\treturn `${u.slice(0, at)}${token}${u.slice(at)}`;\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tdata-test=\"restapi-url\"\n\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\tlabelText=\"Request URL\"\n\t\t\t\t\t\tlabelTextBold\n\t\t\t\t\t\tplaceholder=\"https://\"\n\t\t\t\t\t\ttype=\"url\"\n\t\t\t\t\t\tvalue={url}\n\t\t\t\t\t\tonChangeText={setUrl}\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>HTTP method</TitleSmall>\n\t\t\t\t<Dropdown\n\t\t\t\t\tdata-test=\"restapi-method\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\tdropdownWidth=\"399px\"\n\t\t\t\t\toptions={METHOD_OPTIONS}\n\t\t\t\t\tdefaultOptions={[{ label: method, value: method }]}\n\t\t\t\t\tonSelect={(opt) => {\n\t\t\t\t\t\tconst v = unwrapDropdownValue(opt);\n\t\t\t\t\t\tif (v) {\n\t\t\t\t\t\t\tsetMethod(v as RestApiMethod);\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Headers</TitleSmall>\n\t\t\t\t{headers.map((h, i) => (\n\t\t\t\t\t// eslint-disable-next-line react/no-array-index-key\n\t\t\t\t\t<HeaderRow key={i} data-test={`restapi-header-${i}`}>\n\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\t\thideInputHeader\n\t\t\t\t\t\t\tplaceholder=\"Enter name\"\n\t\t\t\t\t\t\tvalue={h.key}\n\t\t\t\t\t\t\tonChangeText={(v) => patchHeader(i, { key: v })}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<VariableTriggerArea\n\t\t\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\t\t\tonInsert={(token, caret) => {\n\t\t\t\t\t\t\t\tconst at = caret ?? h.value.length;\n\t\t\t\t\t\t\t\tpatchHeader(i, {\n\t\t\t\t\t\t\t\t\tvalue: `${h.value.slice(0, at)}${token}${h.value.slice(at)}`,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\t\t\thideInputHeader\n\t\t\t\t\t\t\t\tplaceholder=\"Enter value\"\n\t\t\t\t\t\t\t\tvalue={h.value}\n\t\t\t\t\t\t\t\tonChangeText={(v) => patchHeader(i, { value: v })}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</VariableTriggerArea>\n\t\t\t\t\t\t<IconBtn\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-label=\"Remove header\"\n\t\t\t\t\t\t\tdata-test={`restapi-header-remove-${i}`}\n\t\t\t\t\t\t\tonClick={() => removeHeader(i)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<DeleteIcon\n\t\t\t\t\t\t\t\twidth={16}\n\t\t\t\t\t\t\t\theight={16}\n\t\t\t\t\t\t\t\tcolor={COLORS.content.secondary}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</IconBtn>\n\t\t\t\t\t</HeaderRow>\n\t\t\t\t))}\n\t\t\t\t<AddHeaderRow>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tdata-test=\"restapi-add-header\"\n\t\t\t\t\t\tbuttonType=\"dashRegular\"\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\tLeadingIcon={PlusIcon}\n\t\t\t\t\t\tbuttonText=\"Add header\"\n\t\t\t\t\t\tonClick={addHeader}\n\t\t\t\t\t/>\n\t\t\t\t</AddHeaderRow>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Request </TitleSmall>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\tonInsert={(token) =>\n\t\t\t\t\t\trequestEditorRef.current?.insertInlineContent(token)\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<BikEditor\n\t\t\t\t\t\tref={requestEditorRef}\n\t\t\t\t\t\tfeatures={{ jsonMode: true }}\n\t\t\t\t\t\tinitialContent={requestBody}\n\t\t\t\t\t\tstyle={JsonFieldBox}\n\t\t\t\t\t\tplaceholder=\"Type or paste JSON here\"\n\t\t\t\t\t\tonChange={(c) => setRequestBody(c.text)}\n\t\t\t\t\t\tminHeight=\"120px\"\n\t\t\t\t\t\tmaxHeight=\"240px\"\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Response </TitleSmall>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\tonInsert={(token) =>\n\t\t\t\t\t\tresponseEditorRef.current?.insertInlineContent(token)\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<BikEditor\n\t\t\t\t\t\tref={responseEditorRef}\n\t\t\t\t\t\tfeatures={{ jsonMode: true }}\n\t\t\t\t\t\tstyle={JsonFieldBox}\n\t\t\t\t\t\tinitialContent={responseSample}\n\t\t\t\t\t\tplaceholder=\"Type or paste JSON here\"\n\t\t\t\t\t\tonChange={(c) => setResponseSample(c.text)}\n\t\t\t\t\t\tminHeight=\"120px\"\n\t\t\t\t\t\tmaxHeight=\"240px\"\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\t\t</SideModal>\n\t);\n};\n\nconst HeaderRow = styled.div`\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n`;\n\nconst AddHeaderRow = styled.div`\n\tdisplay: flex;\n`;\n\nconst IconBtn = styled.button`\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tflex-shrink: 0;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid ${COLORS.stroke.primary};\n\tborder-radius: 4px;\n\tbackground: ${COLORS.surface.standard};\n\tcursor: pointer;\n\n\t&:hover {\n\t\tborder-color: ${COLORS.content.secondary};\n\t}\n`;\n\nexport const JsonFieldBox = {\n\tborderRadius: '4px',\n\toverflow: 'hidden',\n};\n"],"names":["METHODS","METHOD_OPTIONS","m","RestApiToolPanel","onClose","onSave","initial","onImprove","charLimits","AGENT_CHAR_LIMITS","zIndex","existingNames","variablesData","name","setName","useState","requestEditorRef","useRef","responseEditorRef","instructions","setInstructions","url","setUrl","method","setMethod","headers","setHeaders","requestBody","setRequestBody","responseSample","setResponseSample","saving","setSaving","patchHeader","i","patch","prev","h","idx","addHeader","removeHeader","_","nameTrimmed","isDuplicateName","n","canSave","jsxs","SideModal","jsx","DrawerHeaderText","DRAWER_HEADER_STYLE","DRAWER_BODY_STYLE","config","result","Input","ToolInstructionsField","FieldBlock","VariableTriggerArea","token","caret","u","at","TitleSmall","COLORS","Dropdown","opt","v","unwrapDropdownValue","HeaderRow","IconBtn","DeleteIcon","AddHeaderRow","Button","PlusIcon","BikEditor","JsonFieldBox","c","styled"],"mappings":";;;;;;;;;;;;;;;;;;AAkDA,MAAMA,KAA2B,CAAC,OAAO,QAAQ,OAAO,SAAS,QAAQ,GACnEC,KAAiCD,GAAQ,IAAI,CAACE,OAAO;AAAA,EAC1D,OAAOA;AAAA,EACP,OAAOA;AACR,EAAE,GAQWC,KAAoD,CAAC;AAAA,EACjE,SAAAC;AAAA,EACA,QAAAC;AAAA,EACA,SAAAC;AAAA,EACA,WAAAC;AAAA,EACA,YAAAC,IAAaC;AAAA,EACb,QAAAC;AAAA,EACA,eAAAC,IAAgB,CAAA;AAAA,EAChB,eAAAC;AACD,MAAM;AACL,QAAM,CAACC,GAAMC,CAAO,IAAIC,EAAST,GAAS,QAAQ,EAAE,GAE9CU,IAAmBC,EAAqB,IAAI,GAC5CC,IAAoBD,EAAqB,IAAI,GAC7C,CAACE,GAAcC,CAAe,IAAIL,EAAST,GAAS,gBAAgB,EAAE,GAEtE,CAACe,GAAKC,CAAM,IAAIP,EAAST,GAAS,OAAO,UAAU,GACnD,CAACiB,GAAQC,CAAS,IAAIT;AAAA,IAC3BT,GAAS,UAAU;AAAA,EAAA,GAEd,CAACmB,GAASC,CAAU,IAAIX;AAAA,IAC7BT,GAAS,WAAW,CAAC,EAAE,KAAK,IAAI,OAAO,IAAI;AAAA,EAAA,GAEtC,CAACqB,GAAaC,CAAc,IAAIb,EAAST,GAAS,eAAe,EAAE,GACnE,CAACuB,GAAgBC,CAAiB,IAAIf;AAAA,IAC3CT,GAAS,kBAAkB;AAAA,EAAA,GAEtB,CAACyB,GAAQC,CAAS,IAAIjB,EAAS,EAAK,GAEpCkB,IAAc,CAACC,GAAWC,MAC/BT;AAAA,IAAW,CAACU,MACXA,EAAK,IAAI,CAACC,GAAGC,MAASA,MAAQJ,IAAI,EAAE,GAAGG,GAAG,GAAGF,EAAA,IAAUE,CAAE;AAAA,EAAA,GAErDE,IAAY,MACjBb,EAAW,CAACU,MAAS,CAAC,GAAGA,GAAM,EAAE,KAAK,IAAI,OAAO,GAAA,CAAI,CAAC,GACjDI,IAAe,CAACN,MACrBR,EAAW,CAACU,MAASA,EAAK,OAAO,CAACK,GAAGH,MAAQA,MAAQJ,CAAC,CAAC,GAElDQ,IAAc7B,EAAK,KAAA,GAEnB8B,IACLD,EAAY,SAAS,KACrB/B,EAAc;AAAA,IACb,CAACiC,MAAMA,EAAE,KAAA,EAAO,YAAA,MAAkBF,EAAY,YAAA;AAAA,EAAY,GAEtDG,IACLH,EAAY,SAAS,KAAKrB,EAAI,OAAO,SAAS,KAAK,CAACsB;AA4BrD,SACC,gBAAAG;AAAA,IAACC;AAAA,IAAA;AAAA,MACA,QAAO;AAAA,MACP,kBAAkB;AAAA,MAClB,QAAArC;AAAA,MACA,uBACC,gBAAAsC;AAAA,QAACC;AAAA,QAAA;AAAA,UACA,OAAM;AAAA,UACN,UAAS;AAAA,QAAA;AAAA,MAAA;AAAA,MAGX,OAAM;AAAA,MACN,aAAaC;AAAA,MACb,WAAWC;AAAA,MACX,SAAA/C;AAAA,MACA,iBAAiB;AAAA,QAChB,aAAa;AAAA,QACb,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,MAAM;AAAA,QACN,UAAU,CAACyC;AAAA,QACX,WAAWd;AAAA,QACX,SAhDgB,YAAY;AAC9B,cAAI,CAACc,KAAWd;AACf;AAED,gBAAMqB,IAA4B;AAAA,YACjC,IAAI9C,GAAS,MAAM,WAAW,KAAK,MAAM,SAAS,EAAE,CAAC;AAAA,YACrD,MAAMO,EAAK,KAAA;AAAA,YACX,cAAAM;AAAA,YACA,KAAKE,EAAI,KAAA;AAAA,YACT,QAAAE;AAAA;AAAA,YAEA,SAASE,EAAQ,OAAO,CAACY,MAAMA,EAAE,IAAI,UAAUA,EAAE,MAAM,KAAA,CAAM;AAAA,YAC7D,aAAAV;AAAA,YACA,gBAAAE;AAAA,UAAA,GAEKwB,IAAShD,EAAO+C,CAAM;AAC5B,cAAIC,KAAU,OAAQA,EAAyB,QAAS,YAAY;AACnE,YAAArB,EAAU,EAAI;AACd,gBAAI;AACH,oBAAMqB;AAAA,YACP,UAAA;AACC,cAAArB,EAAU,EAAK;AAAA,YAChB;AAAA,UACD;AAAA,QACD;AAAA,MAwBY;AAAA,MAEV,mBAAmB;AAAA,QAClB,aAAa;AAAA,QACb,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,MAAM;AAAA,QACN,SAAS5B;AAAA,MAAA;AAAA,MAGV,UAAA;AAAA,QAAA,gBAAA4C;AAAA,UAACM;AAAA,UAAA;AAAA,YACA,aAAU;AAAA,YACV,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,eAAa;AAAA,YACb,aAAY;AAAA,YACZ,OAAOzC;AAAA,YACP,cAAcL,EAAW;AAAA,YACzB,OAAOmC,IAAkB,YAAY;AAAA,YACrC,cACCA,IAAkB,yCAAyC;AAAA,YAE5D,cAAc7B;AAAA,UAAA;AAAA,QAAA;AAAA,QAGf,gBAAAkC;AAAA,UAACO;AAAA,UAAA;AAAA,YACA,aAAU;AAAA,YACV,OAAM;AAAA,YACN,OAAOpC;AAAA,YACP,UAAUC;AAAA,YACV,WAAWZ,EAAW;AAAA,YACtB,aAAY;AAAA,YACZ,WAAAD;AAAA,YACA,eAAAK;AAAA,UAAA;AAAA,QAAA;AAAA,0BAGA4C,GAAA,EACA,UAAA,gBAAAR;AAAA,UAACS;AAAA,UAAA;AAAA,YACA,eAAA7C;AAAA,YACA,UAAU,CAAC8C,GAAOC,MACjBrC,EAAO,CAACsC,MAAM;AACb,oBAAMC,IAAKF,KAASC,EAAE;AACtB,qBAAO,GAAGA,EAAE,MAAM,GAAGC,CAAE,CAAC,GAAGH,CAAK,GAAGE,EAAE,MAAMC,CAAE,CAAC;AAAA,YAC/C,CAAC;AAAA,YAGF,UAAA,gBAAAb;AAAA,cAACM;AAAA,cAAA;AAAA,gBACA,aAAU;AAAA,gBACV,SAAQ;AAAA,gBACR,WAAU;AAAA,gBACV,eAAa;AAAA,gBACb,aAAY;AAAA,gBACZ,MAAK;AAAA,gBACL,OAAOjC;AAAA,gBACP,cAAcC;AAAA,cAAA;AAAA,YAAA;AAAA,UACf;AAAA,QAAA,GAEF;AAAA,0BAECkC,GAAA,EACA,UAAA;AAAA,UAAA,gBAAAR,EAACc,GAAA,EAAW,OAAOC,EAAO,QAAQ,SAAS,UAAA,eAAW;AAAA,UACtD,gBAAAf;AAAA,YAACgB;AAAA,YAAA;AAAA,cACA,aAAU;AAAA,cACV,MAAK;AAAA,cACL,OAAM;AAAA,cACN,eAAc;AAAA,cACd,SAAS/D;AAAA,cACT,gBAAgB,CAAC,EAAE,OAAOsB,GAAQ,OAAOA,GAAQ;AAAA,cACjD,UAAU,CAAC0C,MAAQ;AAClB,sBAAMC,IAAIC,GAAoBF,CAAG;AACjC,gBAAIC,KACH1C,EAAU0C,CAAkB;AAAA,cAE9B;AAAA,YAAA;AAAA,UAAA;AAAA,QACD,GACD;AAAA,0BAECV,GAAA,EACA,UAAA;AAAA,UAAA,gBAAAR,EAACc,GAAA,EAAW,OAAOC,EAAO,QAAQ,SAAS,UAAA,WAAO;AAAA,UACjDtC,EAAQ,IAAI,CAACY,GAAGH;AAAA;AAAA,YAEhB,gBAAAY,EAACsB,IAAA,EAAkB,aAAW,kBAAkBlC,CAAC,IAChD,UAAA;AAAA,cAAA,gBAAAc;AAAA,gBAACM;AAAA,gBAAA;AAAA,kBACA,SAAQ;AAAA,kBACR,iBAAe;AAAA,kBACf,aAAY;AAAA,kBACZ,OAAOjB,EAAE;AAAA,kBACT,cAAc,CAAC6B,MAAMjC,EAAYC,GAAG,EAAE,KAAKgC,GAAG;AAAA,gBAAA;AAAA,cAAA;AAAA,cAE/C,gBAAAlB;AAAA,gBAACS;AAAA,gBAAA;AAAA,kBACA,eAAA7C;AAAA,kBACA,UAAU,CAAC8C,GAAOC,MAAU;AAC3B,0BAAME,IAAKF,KAAStB,EAAE,MAAM;AAC5B,oBAAAJ,EAAYC,GAAG;AAAA,sBACd,OAAO,GAAGG,EAAE,MAAM,MAAM,GAAGwB,CAAE,CAAC,GAAGH,CAAK,GAAGrB,EAAE,MAAM,MAAMwB,CAAE,CAAC;AAAA,oBAAA,CAC1D;AAAA,kBACF;AAAA,kBAEA,UAAA,gBAAAb;AAAA,oBAACM;AAAA,oBAAA;AAAA,sBACA,SAAQ;AAAA,sBACR,iBAAe;AAAA,sBACf,aAAY;AAAA,sBACZ,OAAOjB,EAAE;AAAA,sBACT,cAAc,CAAC6B,MAAMjC,EAAYC,GAAG,EAAE,OAAOgC,GAAG;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBACjD;AAAA,cAAA;AAAA,cAED,gBAAAlB;AAAA,gBAACqB;AAAA,gBAAA;AAAA,kBACA,MAAK;AAAA,kBACL,cAAW;AAAA,kBACX,aAAW,yBAAyBnC,CAAC;AAAA,kBACrC,SAAS,MAAMM,EAAaN,CAAC;AAAA,kBAE7B,UAAA,gBAAAc;AAAA,oBAACsB;AAAAA,oBAAA;AAAA,sBACA,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,OAAOP,EAAO,QAAQ;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBACvB;AAAA,cAAA;AAAA,YACD,EAAA,GApCe7B,CAqChB;AAAA,WACA;AAAA,4BACAqC,IAAA,EACA,UAAA,gBAAAvB;AAAA,YAACwB;AAAA,YAAA;AAAA,cACA,aAAU;AAAA,cACV,YAAW;AAAA,cACX,MAAK;AAAA,cACL,aAAaC;AAAAA,cACb,YAAW;AAAA,cACX,SAASlC;AAAA,YAAA;AAAA,UAAA,EACV,CACD;AAAA,QAAA,GACD;AAAA,0BAECiB,GAAA,EACA,UAAA;AAAA,UAAA,gBAAAR,EAACc,GAAA,EAAW,OAAOC,EAAO,QAAQ,SAAS,UAAA,YAAQ;AAAA,UACnD,gBAAAf;AAAA,YAACS;AAAA,YAAA;AAAA,cACA,eAAA7C;AAAA,cACA,UAAU,CAAC8C,MACV1C,EAAiB,SAAS,oBAAoB0C,CAAK;AAAA,cAGpD,UAAA,gBAAAV;AAAA,gBAAC0B;AAAA,gBAAA;AAAA,kBACA,KAAK1D;AAAA,kBACL,UAAU,EAAE,UAAU,GAAA;AAAA,kBACtB,gBAAgBW;AAAA,kBAChB,OAAOgD;AAAA,kBACP,aAAY;AAAA,kBACZ,UAAU,CAACC,MAAMhD,EAAegD,EAAE,IAAI;AAAA,kBACtC,WAAU;AAAA,kBACV,WAAU;AAAA,gBAAA;AAAA,cAAA;AAAA,YACX;AAAA,UAAA;AAAA,QACD,GACD;AAAA,0BAECpB,GAAA,EACA,UAAA;AAAA,UAAA,gBAAAR,EAACc,GAAA,EAAW,OAAOC,EAAO,QAAQ,SAAS,UAAA,aAAS;AAAA,UACpD,gBAAAf;AAAA,YAACS;AAAA,YAAA;AAAA,cACA,eAAA7C;AAAA,cACA,UAAU,CAAC8C,MACVxC,EAAkB,SAAS,oBAAoBwC,CAAK;AAAA,cAGrD,UAAA,gBAAAV;AAAA,gBAAC0B;AAAA,gBAAA;AAAA,kBACA,KAAKxD;AAAA,kBACL,UAAU,EAAE,UAAU,GAAA;AAAA,kBACtB,OAAOyD;AAAA,kBACP,gBAAgB9C;AAAA,kBAChB,aAAY;AAAA,kBACZ,UAAU,CAAC+C,MAAM9C,EAAkB8C,EAAE,IAAI;AAAA,kBACzC,WAAU;AAAA,kBACV,WAAU;AAAA,gBAAA;AAAA,cAAA;AAAA,YACX;AAAA,UAAA;AAAA,QACD,EAAA,CACD;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGH,GAEMR,KAAYS,EAAO;AAAA;AAAA;AAAA;AAAA,GAMnBN,KAAeM,EAAO;AAAA;AAAA,GAItBR,KAAUQ,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAOFd,EAAO,OAAO,OAAO;AAAA;AAAA,eAE3BA,EAAO,QAAQ,QAAQ;AAAA;AAAA;AAAA;AAAA,kBAIpBA,EAAO,QAAQ,SAAS;AAAA;AAAA,GAI7BY,IAAe;AAAA,EAC3B,cAAc;AAAA,EACd,UAAU;AACX;"}
|
|
1
|
+
{"version":3,"file":"RestApiToolPanel.js","sources":["../../../../../src/components/agent-builder/components/RestApiToolPanel.tsx"],"sourcesContent":["import DeleteIcon from '@src/assets/icons/delete.svg';\nimport PlusIcon from '@src/assets/icons/plus.svg';\nimport { BikEditor, BikEditorRef } from '@src/editor';\nimport React, { useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { Button } from '@src/components/button';\nimport { Dropdown, unwrapDropdownValue } from '@src/components/dropdown';\nimport { SingleOption } from '@src/components/dropdown/type';\nimport { Input } from '@src/components/input';\nimport { SideModal } from '@src/components/side-modal';\nimport { TitleSmall } from '@src/components/TypographyStyle';\nimport { COLORS } from '@src/constants/Theme';\nimport type { VariableListInterfaceV3 } from '../../variable-picker-v3/model';\nimport {\n\tRestApiHeader,\n\tRestApiMethod,\n\tRestApiToolConfig,\n} from '../AgentBuilder.model';\nimport { FieldBlock } from '../AgentBuilder.styled';\nimport type { AgentCharLimits } from '../constants/charLimits';\nimport { AGENT_CHAR_LIMITS } from '../constants/charLimits';\nimport {\n\tDRAWER_BODY_STYLE,\n\tDRAWER_HEADER_STYLE,\n\tDrawerHeaderText,\n} from './DrawerHeaderText';\nimport { ToolInstructionsField } from './ToolInstructionsField';\nimport { VariableTriggerArea } from './VariableTriggerArea';\n\ninterface RestApiToolPanelProps {\n\tonClose: () => void;\n\t/** Persist the config. A pending promise shows the Save loader. */\n\tonSave: (config: RestApiToolConfig) => void | Promise<void>;\n\t/** Seed values when editing an existing tool. */\n\tinitial?: RestApiToolConfig;\n\t/** Optional \"Improve with AI\" for the instructions field. Omit to hide it. */\n\tonImprove?: (text: string) => Promise<string>;\n\tcharLimits?: AgentCharLimits;\n\t/** SideModal stacking order — raise it when opened over another drawer. */\n\tzIndex?: number;\n\t/** Names of the OTHER tools — a new tool can't reuse one of these. */\n\texistingNames?: string[];\n\t/**\n\t * Variable catalog for the `@` trigger. When non-empty, `@` opens the\n\t * variable picker directly in Instructions / Request URL / header values /\n\t * Request / Response. Absent → the drawer behaves exactly as before.\n\t */\n\tvariablesData?: VariableListInterfaceV3[];\n}\n\nconst METHODS: RestApiMethod[] = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];\nconst METHOD_OPTIONS: SingleOption[] = METHODS.map((m) => ({\n\tlabel: m,\n\tvalue: m,\n}));\n\n/**\n * Keep the Request / Response bodies valid JSON: wrap the picked token in\n * quotes (`\"email\": \"{{variable:customer.email}}\"`) — unless the `@` was typed\n * inside a string literal already (odd number of unescaped `\"` before it, e.g.\n * `\"Bearer @`), where the bare token interpolates into the existing string.\n */\nexport const jsonQuoteToken = (\n\ttoken: string,\n\tctx: { textBefore: string },\n): string => {\n\tconst quotes = ctx.textBefore.match(/(?<!\\\\)\"/g)?.length ?? 0;\n\treturn quotes % 2 === 1 ? token : `\"${token}\"`;\n};\n\n/**\n * Right-side drawer to configure a \"Rest API\" tool: the endpoint the agent can\n * call, plus a JSON request-body template and a sample response. Mount it fresh\n * per open (key it) so `initial` seeds the state. Built on the shared `SideModal`\n * shell and the BikEditor JSON body mode for the Request / Response editors.\n */\nexport const RestApiToolPanel: React.FC<RestApiToolPanelProps> = ({\n\tonClose,\n\tonSave,\n\tinitial,\n\tonImprove,\n\tcharLimits = AGENT_CHAR_LIMITS,\n\tzIndex,\n\texistingNames = [],\n\tvariablesData,\n}) => {\n\tconst [name, setName] = useState(initial?.name ?? '');\n\t// `@`-picked variables insert into the JSON editors at their own cursor.\n\tconst requestEditorRef = useRef<BikEditorRef>(null);\n\tconst responseEditorRef = useRef<BikEditorRef>(null);\n\tconst [instructions, setInstructions] = useState(initial?.instructions ?? '');\n\t// New tools start with the scheme pre-filled so the user only types the host.\n\tconst [url, setUrl] = useState(initial?.url ?? 'https://');\n\tconst [method, setMethod] = useState<RestApiMethod>(\n\t\tinitial?.method ?? 'POST',\n\t);\n\tconst [headers, setHeaders] = useState<RestApiHeader[]>(\n\t\tinitial?.headers ?? [{ key: '', value: '' }],\n\t);\n\tconst [requestBody, setRequestBody] = useState(initial?.requestBody ?? '');\n\tconst [responseSample, setResponseSample] = useState(\n\t\tinitial?.responseSample ?? '',\n\t);\n\tconst [saving, setSaving] = useState(false);\n\n\tconst patchHeader = (i: number, patch: Partial<RestApiHeader>) =>\n\t\tsetHeaders((prev) =>\n\t\t\tprev.map((h, idx) => (idx === i ? { ...h, ...patch } : h)),\n\t\t);\n\tconst addHeader = () =>\n\t\tsetHeaders((prev) => [...prev, { key: '', value: '' }]);\n\tconst removeHeader = (i: number) =>\n\t\tsetHeaders((prev) => prev.filter((_, idx) => idx !== i));\n\n\tconst nameTrimmed = name.trim();\n\t// Case-insensitive: two tools can't share a name (the LLM references them by it).\n\tconst isDuplicateName =\n\t\tnameTrimmed.length > 0 &&\n\t\texistingNames.some(\n\t\t\t(n) => n.trim().toLowerCase() === nameTrimmed.toLowerCase(),\n\t\t);\n\tconst canSave =\n\t\tnameTrimmed.length > 0 && url.trim().length > 0 && !isDuplicateName;\n\n\tconst handleSave = async () => {\n\t\tif (!canSave || saving) {\n\t\t\treturn;\n\t\t}\n\t\tconst config: RestApiToolConfig = {\n\t\t\tid: initial?.id ?? `restapi_${Date.now().toString(36)}`,\n\t\t\tname: name.trim(),\n\t\t\tinstructions,\n\t\t\turl: url.trim(),\n\t\t\tmethod,\n\t\t\t// Drop fully-empty header rows.\n\t\t\theaders: headers.filter((h) => h.key.trim() || h.value.trim()),\n\t\t\trequestBody,\n\t\t\tresponseSample,\n\t\t};\n\t\tconst result = onSave(config);\n\t\tif (result && typeof (result as Promise<void>).then === 'function') {\n\t\t\tsetSaving(true);\n\t\t\ttry {\n\t\t\t\tawait result;\n\t\t\t} finally {\n\t\t\t\tsetSaving(false);\n\t\t\t}\n\t\t}\n\t};\n\n\treturn (\n\t\t<SideModal\n\t\t\theader=\"Rest API\"\n\t\t\tcloseOnEscapeKey={false}\n\t\t\tzIndex={zIndex}\n\t\t\theaderCustomComponent={\n\t\t\t\t<DrawerHeaderText\n\t\t\t\t\ttitle=\"Rest API\"\n\t\t\t\t\tsubtitle=\"Connect to any API endpoint. Define the request and a sample response for the agent to reference.\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\twidth=\"431px\"\n\t\t\theaderStyle={DRAWER_HEADER_STYLE}\n\t\t\tbodyStyle={DRAWER_BODY_STYLE}\n\t\t\tonClose={onClose}\n\t\t\tsaveButtonProps={{\n\t\t\t\t'data-test': 'restapi-save',\n\t\t\t\tbuttonText: 'Save',\n\t\t\t\tbuttonType: 'primary',\n\t\t\t\tsize: 'small',\n\t\t\t\tdisabled: !canSave,\n\t\t\t\tisLoading: saving,\n\t\t\t\tonClick: handleSave,\n\t\t\t}}\n\t\t\tcancelButtonProps={{\n\t\t\t\t'data-test': 'restapi-cancel',\n\t\t\t\tbuttonText: 'Cancel',\n\t\t\t\tbuttonType: 'tertiaryGray',\n\t\t\t\tsize: 'small',\n\t\t\t\tonClick: onClose,\n\t\t\t}}\n\t\t>\n\t\t\t<Input\n\t\t\t\tdata-test=\"restapi-name\"\n\t\t\t\tvariant=\"small\"\n\t\t\t\tlabelText=\"Name\"\n\t\t\t\tlabelTextBold\n\t\t\t\tplaceholder=\"Enter action name\"\n\t\t\t\tvalue={name}\n\t\t\t\tmaxCharLimit={charLimits.name}\n\t\t\t\tstate={isDuplicateName ? 'invalid' : undefined}\n\t\t\t\terrorMessage={\n\t\t\t\t\tisDuplicateName ? 'A tool with this name already exists' : undefined\n\t\t\t\t}\n\t\t\t\tonChangeText={setName}\n\t\t\t/>\n\n\t\t\t<ToolInstructionsField\n\t\t\t\tdata-test=\"restapi-instructions\"\n\t\t\t\tlabel=\"Instructions\"\n\t\t\t\tvalue={instructions}\n\t\t\t\tonChange={setInstructions}\n\t\t\t\tmaxLength={charLimits.instructions}\n\t\t\t\tplaceholder=\"Describe how should the LLM generate the rest API\"\n\t\t\t\tonImprove={onImprove}\n\t\t\t\tvariablesData={variablesData}\n\t\t\t/>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\tonInsert={(token, caret) =>\n\t\t\t\t\t\tsetUrl((u) => {\n\t\t\t\t\t\t\tconst at = caret ?? u.length;\n\t\t\t\t\t\t\treturn `${u.slice(0, at)}${token}${u.slice(at)}`;\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tdata-test=\"restapi-url\"\n\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\tlabelText=\"Request URL\"\n\t\t\t\t\t\tlabelTextBold\n\t\t\t\t\t\tplaceholder=\"https://\"\n\t\t\t\t\t\ttype=\"url\"\n\t\t\t\t\t\tvalue={url}\n\t\t\t\t\t\tonChangeText={setUrl}\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>HTTP method</TitleSmall>\n\t\t\t\t<Dropdown\n\t\t\t\t\tdata-test=\"restapi-method\"\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\tdropdownWidth=\"399px\"\n\t\t\t\t\toptions={METHOD_OPTIONS}\n\t\t\t\t\tdefaultOptions={[{ label: method, value: method }]}\n\t\t\t\t\tonSelect={(opt) => {\n\t\t\t\t\t\tconst v = unwrapDropdownValue(opt);\n\t\t\t\t\t\tif (v) {\n\t\t\t\t\t\t\tsetMethod(v as RestApiMethod);\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Headers</TitleSmall>\n\t\t\t\t{headers.map((h, i) => (\n\t\t\t\t\t// eslint-disable-next-line react/no-array-index-key\n\t\t\t\t\t<HeaderRow key={i} data-test={`restapi-header-${i}`}>\n\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\t\thideInputHeader\n\t\t\t\t\t\t\tplaceholder=\"Enter name\"\n\t\t\t\t\t\t\tvalue={h.key}\n\t\t\t\t\t\t\tonChangeText={(v) => patchHeader(i, { key: v })}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<VariableTriggerArea\n\t\t\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\t\t\tonInsert={(token, caret) => {\n\t\t\t\t\t\t\t\tconst at = caret ?? h.value.length;\n\t\t\t\t\t\t\t\tpatchHeader(i, {\n\t\t\t\t\t\t\t\t\tvalue: `${h.value.slice(0, at)}${token}${h.value.slice(at)}`,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tvariant=\"small\"\n\t\t\t\t\t\t\t\thideInputHeader\n\t\t\t\t\t\t\t\tplaceholder=\"Enter value\"\n\t\t\t\t\t\t\t\tvalue={h.value}\n\t\t\t\t\t\t\t\tonChangeText={(v) => patchHeader(i, { value: v })}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</VariableTriggerArea>\n\t\t\t\t\t\t<IconBtn\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-label=\"Remove header\"\n\t\t\t\t\t\t\tdata-test={`restapi-header-remove-${i}`}\n\t\t\t\t\t\t\tonClick={() => removeHeader(i)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<DeleteIcon\n\t\t\t\t\t\t\t\twidth={16}\n\t\t\t\t\t\t\t\theight={16}\n\t\t\t\t\t\t\t\tcolor={COLORS.content.secondary}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</IconBtn>\n\t\t\t\t\t</HeaderRow>\n\t\t\t\t))}\n\t\t\t\t<AddHeaderRow>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tdata-test=\"restapi-add-header\"\n\t\t\t\t\t\tbuttonType=\"dashRegular\"\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\tLeadingIcon={PlusIcon}\n\t\t\t\t\t\tbuttonText=\"Add header\"\n\t\t\t\t\t\tonClick={addHeader}\n\t\t\t\t\t/>\n\t\t\t\t</AddHeaderRow>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Request </TitleSmall>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\ttransformToken={jsonQuoteToken}\n\t\t\t\t\tonInsert={(token) =>\n\t\t\t\t\t\trequestEditorRef.current?.insertInlineContent(token)\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<BikEditor\n\t\t\t\t\t\tref={requestEditorRef}\n\t\t\t\t\t\tfeatures={{ jsonMode: true }}\n\t\t\t\t\t\tinitialContent={requestBody}\n\t\t\t\t\t\tstyle={JsonFieldBox}\n\t\t\t\t\t\tplaceholder=\"Type or paste JSON here\"\n\t\t\t\t\t\tonChange={(c) => setRequestBody(c.text)}\n\t\t\t\t\t\tminHeight=\"120px\"\n\t\t\t\t\t\tmaxHeight=\"240px\"\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\n\t\t\t<FieldBlock>\n\t\t\t\t<TitleSmall color={COLORS.content.primary}>Response </TitleSmall>\n\t\t\t\t<VariableTriggerArea\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\ttransformToken={jsonQuoteToken}\n\t\t\t\t\tonInsert={(token) =>\n\t\t\t\t\t\tresponseEditorRef.current?.insertInlineContent(token)\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<BikEditor\n\t\t\t\t\t\tref={responseEditorRef}\n\t\t\t\t\t\tfeatures={{ jsonMode: true }}\n\t\t\t\t\t\tstyle={JsonFieldBox}\n\t\t\t\t\t\tinitialContent={responseSample}\n\t\t\t\t\t\tplaceholder=\"Type or paste JSON here\"\n\t\t\t\t\t\tonChange={(c) => setResponseSample(c.text)}\n\t\t\t\t\t\tminHeight=\"120px\"\n\t\t\t\t\t\tmaxHeight=\"240px\"\n\t\t\t\t\t/>\n\t\t\t\t</VariableTriggerArea>\n\t\t\t</FieldBlock>\n\t\t</SideModal>\n\t);\n};\n\nconst HeaderRow = styled.div`\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n`;\n\nconst AddHeaderRow = styled.div`\n\tdisplay: flex;\n`;\n\nconst IconBtn = styled.button`\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tflex-shrink: 0;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid ${COLORS.stroke.primary};\n\tborder-radius: 4px;\n\tbackground: ${COLORS.surface.standard};\n\tcursor: pointer;\n\n\t&:hover {\n\t\tborder-color: ${COLORS.content.secondary};\n\t}\n`;\n\nexport const JsonFieldBox = {\n\tborderRadius: '4px',\n\toverflow: 'hidden',\n};\n"],"names":["METHODS","METHOD_OPTIONS","m","jsonQuoteToken","token","ctx","RestApiToolPanel","onClose","onSave","initial","onImprove","charLimits","AGENT_CHAR_LIMITS","zIndex","existingNames","variablesData","name","setName","useState","requestEditorRef","useRef","responseEditorRef","instructions","setInstructions","url","setUrl","method","setMethod","headers","setHeaders","requestBody","setRequestBody","responseSample","setResponseSample","saving","setSaving","patchHeader","i","patch","prev","h","idx","addHeader","removeHeader","_","nameTrimmed","isDuplicateName","n","canSave","jsxs","SideModal","jsx","DrawerHeaderText","DRAWER_HEADER_STYLE","DRAWER_BODY_STYLE","config","result","Input","ToolInstructionsField","FieldBlock","VariableTriggerArea","caret","u","at","TitleSmall","COLORS","Dropdown","opt","v","unwrapDropdownValue","HeaderRow","IconBtn","DeleteIcon","AddHeaderRow","Button","PlusIcon","BikEditor","JsonFieldBox","c","styled"],"mappings":"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"}
|
|
@@ -11,6 +11,15 @@ interface VariableTriggerAreaProps {
|
|
|
11
11
|
* null for rich-editor targets (insert at the editor's own cursor).
|
|
12
12
|
*/
|
|
13
13
|
onInsert: (token: string, caret: number | null) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Rewrite the token before it's handed to `onInsert` — e.g. the Rest API
|
|
16
|
+
* JSON editors wrap it in quotes. `textBefore` is the text preceding the
|
|
17
|
+
* `@` (for input targets the whole value up to the caret; for rich-editor
|
|
18
|
+
* targets just the current text-node fragment).
|
|
19
|
+
*/
|
|
20
|
+
transformToken?: (token: string, ctx: {
|
|
21
|
+
textBefore: string;
|
|
22
|
+
}) => string;
|
|
14
23
|
children: React.ReactNode;
|
|
15
24
|
}
|
|
16
25
|
/**
|
|
@@ -1,70 +1,94 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { useRef as
|
|
1
|
+
import { jsxs as x, jsx as f } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as b, useState as h, useCallback as w, useEffect as k } from "react";
|
|
3
3
|
import m from "styled-components";
|
|
4
|
-
import { PickerType as
|
|
5
|
-
import { variableTokenName as
|
|
6
|
-
import { VariablePicker as
|
|
7
|
-
const
|
|
4
|
+
import { PickerType as B } from "../../variable-picker-v3/model.js";
|
|
5
|
+
import { variableTokenName as y } from "../utils/mentionSerialization.js";
|
|
6
|
+
import { VariablePicker as E } from "../../variable-picker-v3/VariablePicker.js";
|
|
7
|
+
const T = (e) => `{{variable:${y(e.actualValue)}}}`, d = /[\s,;:/?&=(){}[\]"'<>]/, R = (e) => {
|
|
8
8
|
if (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement) {
|
|
9
9
|
const t = e.selectionStart ?? e.value.length, i = t === 0 ? " " : e.value[t - 1] ?? " ";
|
|
10
|
-
return {
|
|
10
|
+
return {
|
|
11
|
+
ok: d.test(i),
|
|
12
|
+
caret: t,
|
|
13
|
+
textBefore: e.value.slice(0, t)
|
|
14
|
+
};
|
|
11
15
|
}
|
|
12
|
-
const
|
|
13
|
-
return {
|
|
14
|
-
|
|
16
|
+
const l = window.getSelection(), c = l?.anchorNode?.textContent ?? "", s = l?.anchorOffset ?? 0, a = s === 0 ? " " : c[s - 1] ?? " ";
|
|
17
|
+
return {
|
|
18
|
+
ok: d.test(a),
|
|
19
|
+
caret: null,
|
|
20
|
+
textBefore: c.slice(0, s)
|
|
21
|
+
};
|
|
22
|
+
}, N = ({
|
|
15
23
|
variablesData: e,
|
|
16
|
-
onInsert:
|
|
17
|
-
|
|
24
|
+
onInsert: l,
|
|
25
|
+
transformToken: c,
|
|
26
|
+
children: s
|
|
18
27
|
}) => {
|
|
19
|
-
const
|
|
20
|
-
(
|
|
21
|
-
if (!
|
|
28
|
+
const a = b(null), [t, i] = h(null), u = (e?.length ?? 0) > 0, p = w(
|
|
29
|
+
(o) => {
|
|
30
|
+
if (!u || o.key !== "@")
|
|
22
31
|
return;
|
|
23
|
-
const
|
|
24
|
-
if (!
|
|
32
|
+
const r = R(o.target);
|
|
33
|
+
if (!r.ok)
|
|
25
34
|
return;
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
35
|
+
o.preventDefault(), o.stopPropagation();
|
|
36
|
+
const n = a.current?.getBoundingClientRect(), g = !!n && window.innerHeight - n.bottom < 340, v = !!n && window.innerWidth - n.left < 360;
|
|
37
|
+
i({
|
|
38
|
+
caret: r.caret,
|
|
39
|
+
textBefore: r.textBefore,
|
|
40
|
+
above: g,
|
|
41
|
+
alignRight: v
|
|
42
|
+
});
|
|
29
43
|
},
|
|
30
|
-
[
|
|
44
|
+
[u]
|
|
31
45
|
);
|
|
32
|
-
return
|
|
33
|
-
if (!
|
|
46
|
+
return k(() => {
|
|
47
|
+
if (!t)
|
|
34
48
|
return;
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
},
|
|
38
|
-
|
|
49
|
+
const o = (n) => {
|
|
50
|
+
n.key === "Escape" && (n.stopPropagation(), i(null));
|
|
51
|
+
}, r = (n) => {
|
|
52
|
+
a.current?.contains(n.target) || i(null);
|
|
39
53
|
};
|
|
40
|
-
return document.addEventListener("keydown",
|
|
41
|
-
document.removeEventListener("keydown",
|
|
54
|
+
return document.addEventListener("keydown", o, !0), document.addEventListener("mousedown", r), () => {
|
|
55
|
+
document.removeEventListener("keydown", o, !0), document.removeEventListener("mousedown", r);
|
|
42
56
|
};
|
|
43
|
-
}, [
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
}, [t]), /* @__PURE__ */ x(L, { ref: a, onKeyDownCapture: p, children: [
|
|
58
|
+
s,
|
|
59
|
+
t && /* @__PURE__ */ f(
|
|
60
|
+
$,
|
|
47
61
|
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
$above: t.above,
|
|
63
|
+
$right: t.alignRight,
|
|
64
|
+
"data-test": "variable-trigger-panel",
|
|
65
|
+
children: /* @__PURE__ */ f(
|
|
66
|
+
E,
|
|
67
|
+
{
|
|
68
|
+
type: B.FLOATER,
|
|
69
|
+
data: e ?? [],
|
|
70
|
+
showRecommendedBar: !1,
|
|
71
|
+
onClose: () => i(null),
|
|
72
|
+
onSelect: (o) => {
|
|
73
|
+
i(null);
|
|
74
|
+
const r = T(o), n = c ? c(r, { textBefore: t.textBefore }) : r;
|
|
75
|
+
l(n, t.caret);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
)
|
|
55
79
|
}
|
|
56
|
-
)
|
|
80
|
+
)
|
|
57
81
|
] });
|
|
58
82
|
}, L = m.div`
|
|
59
83
|
position: relative;
|
|
60
|
-
`,
|
|
84
|
+
`, $ = m.div`
|
|
61
85
|
position: absolute;
|
|
62
|
-
left: 0;
|
|
63
86
|
z-index: 1000;
|
|
87
|
+
${(e) => e.$right ? "right: 0;" : "left: 0;"}
|
|
64
88
|
${(e) => e.$above ? "bottom: calc(100% + 4px);" : "top: calc(100% + 4px);"}
|
|
65
89
|
`;
|
|
66
90
|
export {
|
|
67
|
-
|
|
68
|
-
|
|
91
|
+
N as VariableTriggerArea,
|
|
92
|
+
T as variableToken
|
|
69
93
|
};
|
|
70
94
|
//# sourceMappingURL=VariableTriggerArea.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VariableTriggerArea.js","sources":["../../../../../src/components/agent-builder/components/VariableTriggerArea.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { VariablePicker } from '../../variable-picker-v3';\nimport { PickerType } from '../../variable-picker-v3/model';\nimport type {\n\tVariableListInterfaceV3,\n\tVariableV3,\n} from '../../variable-picker-v3/model';\nimport { variableTokenName } from '../utils/mentionSerialization';\n\n/** The persisted form of a picked variable (`{{variable:<name>}}`). */\nexport const variableToken = (variable: VariableV3): string =>\n\t`{{variable:${variableTokenName(variable.actualValue)}}}`;\n\n/**\n * Boundary test for the `@` trigger: an `@` typed at the start of the field or\n * after a separator opens the picker. The separator set covers URL and JSON\n * delimiters too (`https://@`, `Bearer=@`, `\"@`, `[@`) — an email address's `@`\n * always follows a letter / digit / dot, so `john@acme.com` still types\n * through untouched. Returns the caret index for input / textarea targets\n * (where the caller can splice the token in), null for contenteditable ones.\n */\nconst BOUNDARY = /[\\s,;:/?&=(){}[\\]\"'<>]/;\n\nconst triggerContext = (\n\ttarget: EventTarget | null,\n): { ok: boolean; caret: number | null } => {\n\tif (\n\t\ttarget instanceof HTMLInputElement ||\n\t\ttarget instanceof HTMLTextAreaElement\n\t) {\n\t\tconst caret = target.selectionStart ?? target.value.length;\n\t\tconst prev = caret === 0 ? ' ' : target.value[caret - 1] ?? ' ';\n\t\treturn { ok: BOUNDARY.test(prev), caret };\n\t}\n\t// Rich editor (ProseMirror contenteditable): read the character before the\n\t// selection.\n\tconst sel = window.getSelection();\n\tconst text = sel?.anchorNode?.textContent ?? '';\n\tconst offset = sel?.anchorOffset ?? 0;\n\tconst prev = offset === 0 ? ' ' : text[offset - 1] ?? ' ';\n\treturn { ok: BOUNDARY.test(prev), caret: null };\n};\n\ninterface VariableTriggerAreaProps {\n\t/** Variable catalog. Absent / empty → the wrapper is inert (children only). */\n\tvariablesData?: VariableListInterfaceV3[];\n\t/**\n\t * Insert `token` into the wrapped field. `caret` is the character index the\n\t * `@` was typed at (input / textarea targets — splice the token in there);\n\t * null for rich-editor targets (insert at the editor's own cursor).\n\t */\n\tonInsert: (token: string, caret: number | null) => void;\n\tchildren: React.ReactNode;\n}\n\n/**\n * Wraps any plain field (input / textarea / chips entry / BikEditor) and opens\n * the shared {@link VariablePicker} as a floating panel when `@` is typed at a\n * word boundary. The `@` keystroke itself is swallowed (never reaches the\n * field); picking a variable calls `onInsert` with the `{{variable:<name>}}`\n * token, and Escape / click-outside / the panel's ✕ just closes the panel.\n *\n * Purely presentational wrapper — it renders a `position: relative` block, so\n * the wrapped field must be happy inside a plain block container.\n */\nexport const VariableTriggerArea: React.FC<VariableTriggerAreaProps> = ({\n\tvariablesData,\n\tonInsert,\n\tchildren,\n}) => {\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\t// Non-null while the panel is open: where to put the token when picked, and\n\t// whether the panel renders above the field (not enough room below).\n\tconst [trigger, setTrigger] = useState<{\n\t\tcaret: number | null;\n\t\tabove: boolean;\n\t} | null>(null);\n\n\tconst enabled = (variablesData?.length ?? 0) > 0;\n\n\tconst onKeyDownCapture = useCallback(\n\t\t(e: React.KeyboardEvent) => {\n\t\t\tif (!enabled || e.key !== '@') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst ctx = triggerContext(e.target);\n\t\t\tif (!ctx.ok) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Swallow the `@` so the field's value stays untouched while picking.\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tconst rect = containerRef.current?.getBoundingClientRect();\n\t\t\tconst above = !!rect && window.innerHeight - rect.bottom < 340;\n\t\t\tsetTrigger({ caret: ctx.caret, above });\n\t\t},\n\t\t[enabled],\n\t);\n\n\t// Escape / click-outside dismiss, active only while open.\n\tuseEffect(() => {\n\t\tif (!trigger) {\n\t\t\treturn;\n\t\t}\n\t\tconst onKey = (e: KeyboardEvent) => {\n\t\t\tif (e.key === 'Escape') {\n\t\t\t\te.stopPropagation();\n\t\t\t\tsetTrigger(null);\n\t\t\t}\n\t\t};\n\t\tconst onDown = (e: MouseEvent) => {\n\t\t\tif (!containerRef.current?.contains(e.target as Node)) {\n\t\t\t\tsetTrigger(null);\n\t\t\t}\n\t\t};\n\t\t// Capture phase so an Escape meant for the panel never also closes the\n\t\t// drawer underneath.\n\t\tdocument.addEventListener('keydown', onKey, true);\n\t\tdocument.addEventListener('mousedown', onDown);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('keydown', onKey, true);\n\t\t\tdocument.removeEventListener('mousedown', onDown);\n\t\t};\n\t}, [trigger]);\n\n\treturn (\n\t\t<TriggerWrap ref={containerRef} onKeyDownCapture={onKeyDownCapture}>\n\t\t\t{children}\n\t\t\t{trigger && (\n\t\t\t\t<FloaterBox $above={trigger.above} data-test=\"variable-trigger-panel\">\n\t\t\t\t\t<VariablePicker\n\t\t\t\t\t\ttype={PickerType.FLOATER}\n\t\t\t\t\t\tdata={variablesData ?? []}\n\t\t\t\t\t\tshowRecommendedBar={false}\n\t\t\t\t\t\tonClose={() => setTrigger(null)}\n\t\t\t\t\t\tonSelect={(variable: VariableV3) => {\n\t\t\t\t\t\t\tsetTrigger(null);\n\t\t\t\t\t\t\tonInsert(variableToken(variable), trigger.caret);\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</FloaterBox>\n\t\t\t)}\n\t\t</TriggerWrap>\n\t);\n};\n\nconst TriggerWrap = styled.div`\n\tposition: relative;\n`;\n\n// Floats under (or over) the wrapped field; VariablePicker brings its own card\n// styling. High z-index: these fields live inside side-modal drawers.\nconst FloaterBox = styled.div<{ $above: boolean }>`\n\tposition: absolute;\n\tleft: 0;\n\tz-index: 1000;\n\t${(p) => (p.$above ? 'bottom: calc(100% + 4px);' : 'top: calc(100% + 4px);')}\n`;\n"],"names":["variableToken","variable","variableTokenName","BOUNDARY","triggerContext","target","caret","prev","sel","text","offset","VariableTriggerArea","variablesData","onInsert","children","containerRef","useRef","trigger","setTrigger","useState","enabled","onKeyDownCapture","useCallback","e","ctx","rect","above","useEffect","onKey","onDown","jsxs","TriggerWrap","jsx","FloaterBox","VariablePicker","PickerType","styled","p"],"mappings":";;;;;;AAWO,MAAMA,IAAgB,CAACC,MAC7B,cAAcC,EAAkBD,EAAS,WAAW,CAAC,MAUhDE,IAAW,0BAEXC,IAAiB,CACtBC,MAC2C;AAC3C,MACCA,aAAkB,oBAClBA,aAAkB,qBACjB;AACD,UAAMC,IAAQD,EAAO,kBAAkBA,EAAO,MAAM,QAC9CE,IAAOD,MAAU,IAAI,MAAMD,EAAO,MAAMC,IAAQ,CAAC,KAAK;AAC5D,WAAO,EAAE,IAAIH,EAAS,KAAKI,CAAI,GAAG,OAAAD,EAAA;AAAA,EACnC;AAGA,QAAME,IAAM,OAAO,aAAA,GACbC,IAAOD,GAAK,YAAY,eAAe,IACvCE,IAASF,GAAK,gBAAgB,GAC9BD,IAAOG,MAAW,IAAI,MAAMD,EAAKC,IAAS,CAAC,KAAK;AACtD,SAAO,EAAE,IAAIP,EAAS,KAAKI,CAAI,GAAG,OAAO,KAAA;AAC1C,GAwBaI,IAA0D,CAAC;AAAA,EACvE,eAAAC;AAAA,EACA,UAAAC;AAAA,EACA,UAAAC;AACD,MAAM;AACL,QAAMC,IAAeC,EAAuB,IAAI,GAG1C,CAACC,GAASC,CAAU,IAAIC,EAGpB,IAAI,GAERC,KAAWR,GAAe,UAAU,KAAK,GAEzCS,IAAmBC;AAAA,IACxB,CAACC,MAA2B;AAC3B,UAAI,CAACH,KAAWG,EAAE,QAAQ;AACzB;AAED,YAAMC,IAAMpB,EAAemB,EAAE,MAAM;AACnC,UAAI,CAACC,EAAI;AACR;AAGD,MAAAD,EAAE,eAAA,GACFA,EAAE,gBAAA;AACF,YAAME,IAAOV,EAAa,SAAS,sBAAA,GAC7BW,IAAQ,CAAC,CAACD,KAAQ,OAAO,cAAcA,EAAK,SAAS;AAC3D,MAAAP,EAAW,EAAE,OAAOM,EAAI,OAAO,OAAAE,GAAO;AAAA,IACvC;AAAA,IACA,CAACN,CAAO;AAAA,EAAA;AAIT,SAAAO,EAAU,MAAM;AACf,QAAI,CAACV;AACJ;AAED,UAAMW,IAAQ,CAACL,MAAqB;AACnC,MAAIA,EAAE,QAAQ,aACbA,EAAE,gBAAA,GACFL,EAAW,IAAI;AAAA,IAEjB,GACMW,IAAS,CAACN,MAAkB;AACjC,MAAKR,EAAa,SAAS,SAASQ,EAAE,MAAc,KACnDL,EAAW,IAAI;AAAA,IAEjB;AAGA,oBAAS,iBAAiB,WAAWU,GAAO,EAAI,GAChD,SAAS,iBAAiB,aAAaC,CAAM,GACtC,MAAM;AACZ,eAAS,oBAAoB,WAAWD,GAAO,EAAI,GACnD,SAAS,oBAAoB,aAAaC,CAAM;AAAA,IACjD;AAAA,EACD,GAAG,CAACZ,CAAO,CAAC,GAGX,gBAAAa,EAACC,GAAA,EAAY,KAAKhB,GAAc,kBAAAM,GAC9B,UAAA;AAAA,IAAAP;AAAA,IACAG,KACA,gBAAAe,EAACC,GAAA,EAAW,QAAQhB,EAAQ,OAAO,aAAU,0BAC5C,UAAA,gBAAAe;AAAA,MAACE;AAAA,MAAA;AAAA,QACA,MAAMC,EAAW;AAAA,QACjB,MAAMvB,KAAiB,CAAA;AAAA,QACvB,oBAAoB;AAAA,QACpB,SAAS,MAAMM,EAAW,IAAI;AAAA,QAC9B,UAAU,CAACjB,MAAyB;AACnC,UAAAiB,EAAW,IAAI,GACfL,EAASb,EAAcC,CAAQ,GAAGgB,EAAQ,KAAK;AAAA,QAChD;AAAA,MAAA;AAAA,IAAA,EACD,CACD;AAAA,EAAA,GAEF;AAEF,GAEMc,IAAcK,EAAO;AAAA;AAAA,GAMrBH,IAAaG,EAAO;AAAA;AAAA;AAAA;AAAA,GAIvB,CAACC,MAAOA,EAAE,SAAS,8BAA8B,wBAAyB;AAAA;"}
|
|
1
|
+
{"version":3,"file":"VariableTriggerArea.js","sources":["../../../../../src/components/agent-builder/components/VariableTriggerArea.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { VariablePicker } from '../../variable-picker-v3';\nimport { PickerType } from '../../variable-picker-v3/model';\nimport type {\n\tVariableListInterfaceV3,\n\tVariableV3,\n} from '../../variable-picker-v3/model';\nimport { variableTokenName } from '../utils/mentionSerialization';\n\n/** The persisted form of a picked variable (`{{variable:<name>}}`). */\nexport const variableToken = (variable: VariableV3): string =>\n\t`{{variable:${variableTokenName(variable.actualValue)}}}`;\n\n/**\n * Boundary test for the `@` trigger: an `@` typed at the start of the field or\n * after a separator opens the picker. The separator set covers URL and JSON\n * delimiters too (`https://@`, `Bearer=@`, `\"@`, `[@`) — an email address's `@`\n * always follows a letter / digit / dot, so `john@acme.com` still types\n * through untouched. Returns the caret index for input / textarea targets\n * (where the caller can splice the token in), null for contenteditable ones.\n */\nconst BOUNDARY = /[\\s,;:/?&=(){}[\\]\"'<>]/;\n\nconst triggerContext = (\n\ttarget: EventTarget | null,\n): { ok: boolean; caret: number | null; textBefore: string } => {\n\tif (\n\t\ttarget instanceof HTMLInputElement ||\n\t\ttarget instanceof HTMLTextAreaElement\n\t) {\n\t\tconst caret = target.selectionStart ?? target.value.length;\n\t\tconst prev = caret === 0 ? ' ' : target.value[caret - 1] ?? ' ';\n\t\treturn {\n\t\t\tok: BOUNDARY.test(prev),\n\t\t\tcaret,\n\t\t\ttextBefore: target.value.slice(0, caret),\n\t\t};\n\t}\n\t// Rich editor (ProseMirror contenteditable): read the character before the\n\t// selection. `textBefore` is only the current text-node fragment (fine for\n\t// the token transforms, which just look at nearby characters).\n\tconst sel = window.getSelection();\n\tconst text = sel?.anchorNode?.textContent ?? '';\n\tconst offset = sel?.anchorOffset ?? 0;\n\tconst prev = offset === 0 ? ' ' : text[offset - 1] ?? ' ';\n\treturn {\n\t\tok: BOUNDARY.test(prev),\n\t\tcaret: null,\n\t\ttextBefore: text.slice(0, offset),\n\t};\n};\n\ninterface VariableTriggerAreaProps {\n\t/** Variable catalog. Absent / empty → the wrapper is inert (children only). */\n\tvariablesData?: VariableListInterfaceV3[];\n\t/**\n\t * Insert `token` into the wrapped field. `caret` is the character index the\n\t * `@` was typed at (input / textarea targets — splice the token in there);\n\t * null for rich-editor targets (insert at the editor's own cursor).\n\t */\n\tonInsert: (token: string, caret: number | null) => void;\n\t/**\n\t * Rewrite the token before it's handed to `onInsert` — e.g. the Rest API\n\t * JSON editors wrap it in quotes. `textBefore` is the text preceding the\n\t * `@` (for input targets the whole value up to the caret; for rich-editor\n\t * targets just the current text-node fragment).\n\t */\n\ttransformToken?: (token: string, ctx: { textBefore: string }) => string;\n\tchildren: React.ReactNode;\n}\n\n/**\n * Wraps any plain field (input / textarea / chips entry / BikEditor) and opens\n * the shared {@link VariablePicker} as a floating panel when `@` is typed at a\n * word boundary. The `@` keystroke itself is swallowed (never reaches the\n * field); picking a variable calls `onInsert` with the `{{variable:<name>}}`\n * token, and Escape / click-outside / the panel's ✕ just closes the panel.\n *\n * Purely presentational wrapper — it renders a `position: relative` block, so\n * the wrapped field must be happy inside a plain block container.\n */\nexport const VariableTriggerArea: React.FC<VariableTriggerAreaProps> = ({\n\tvariablesData,\n\tonInsert,\n\ttransformToken,\n\tchildren,\n}) => {\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\t// Non-null while the panel is open: where to put the token when picked, and\n\t// which way the panel flips to stay on screen (above when there's no room\n\t// below, right-aligned when the field sits too close to the right edge —\n\t// e.g. header-value inputs in the Rest API drawer).\n\tconst [trigger, setTrigger] = useState<{\n\t\tcaret: number | null;\n\t\ttextBefore: string;\n\t\tabove: boolean;\n\t\talignRight: boolean;\n\t} | null>(null);\n\n\tconst enabled = (variablesData?.length ?? 0) > 0;\n\n\tconst onKeyDownCapture = useCallback(\n\t\t(e: React.KeyboardEvent) => {\n\t\t\tif (!enabled || e.key !== '@') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst ctx = triggerContext(e.target);\n\t\t\tif (!ctx.ok) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Swallow the `@` so the field's value stays untouched while picking.\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tconst rect = containerRef.current?.getBoundingClientRect();\n\t\t\tconst above = !!rect && window.innerHeight - rect.bottom < 340;\n\t\t\t// Panel is ~344px wide, anchored to the field's left edge — flip to the\n\t\t\t// right edge when that would spill past the viewport (avoids the drawer\n\t\t\t// growing a horizontal scrollbar).\n\t\t\tconst alignRight = !!rect && window.innerWidth - rect.left < 360;\n\t\t\tsetTrigger({\n\t\t\t\tcaret: ctx.caret,\n\t\t\t\ttextBefore: ctx.textBefore,\n\t\t\t\tabove,\n\t\t\t\talignRight,\n\t\t\t});\n\t\t},\n\t\t[enabled],\n\t);\n\n\t// Escape / click-outside dismiss, active only while open.\n\tuseEffect(() => {\n\t\tif (!trigger) {\n\t\t\treturn;\n\t\t}\n\t\tconst onKey = (e: KeyboardEvent) => {\n\t\t\tif (e.key === 'Escape') {\n\t\t\t\te.stopPropagation();\n\t\t\t\tsetTrigger(null);\n\t\t\t}\n\t\t};\n\t\tconst onDown = (e: MouseEvent) => {\n\t\t\tif (!containerRef.current?.contains(e.target as Node)) {\n\t\t\t\tsetTrigger(null);\n\t\t\t}\n\t\t};\n\t\t// Capture phase so an Escape meant for the panel never also closes the\n\t\t// drawer underneath.\n\t\tdocument.addEventListener('keydown', onKey, true);\n\t\tdocument.addEventListener('mousedown', onDown);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('keydown', onKey, true);\n\t\t\tdocument.removeEventListener('mousedown', onDown);\n\t\t};\n\t}, [trigger]);\n\n\treturn (\n\t\t<TriggerWrap ref={containerRef} onKeyDownCapture={onKeyDownCapture}>\n\t\t\t{children}\n\t\t\t{trigger && (\n\t\t\t\t<FloaterBox\n\t\t\t\t\t$above={trigger.above}\n\t\t\t\t\t$right={trigger.alignRight}\n\t\t\t\t\tdata-test=\"variable-trigger-panel\"\n\t\t\t\t>\n\t\t\t\t\t<VariablePicker\n\t\t\t\t\t\ttype={PickerType.FLOATER}\n\t\t\t\t\t\tdata={variablesData ?? []}\n\t\t\t\t\t\tshowRecommendedBar={false}\n\t\t\t\t\t\tonClose={() => setTrigger(null)}\n\t\t\t\t\t\tonSelect={(variable: VariableV3) => {\n\t\t\t\t\t\t\tsetTrigger(null);\n\t\t\t\t\t\t\tconst raw = variableToken(variable);\n\t\t\t\t\t\t\tconst token = transformToken\n\t\t\t\t\t\t\t\t? transformToken(raw, { textBefore: trigger.textBefore })\n\t\t\t\t\t\t\t\t: raw;\n\t\t\t\t\t\t\tonInsert(token, trigger.caret);\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</FloaterBox>\n\t\t\t)}\n\t\t</TriggerWrap>\n\t);\n};\n\nconst TriggerWrap = styled.div`\n\tposition: relative;\n`;\n\n// Floats under (or over) the wrapped field; VariablePicker brings its own card\n// styling. High z-index: these fields live inside side-modal drawers.\nconst FloaterBox = styled.div<{ $above: boolean; $right: boolean }>`\n\tposition: absolute;\n\tz-index: 1000;\n\t${(p) => (p.$right ? 'right: 0;' : 'left: 0;')}\n\t${(p) => (p.$above ? 'bottom: calc(100% + 4px);' : 'top: calc(100% + 4px);')}\n`;\n"],"names":["variableToken","variable","variableTokenName","BOUNDARY","triggerContext","target","caret","prev","sel","text","offset","VariableTriggerArea","variablesData","onInsert","transformToken","children","containerRef","useRef","trigger","setTrigger","useState","enabled","onKeyDownCapture","useCallback","e","ctx","rect","above","alignRight","useEffect","onKey","onDown","jsxs","TriggerWrap","jsx","FloaterBox","VariablePicker","PickerType","raw","token","styled","p"],"mappings":"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"}
|