myoperator-ui 0.0.212 → 0.0.213
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/index.js +459 -124
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3057,6 +3057,8 @@ export interface CreatableSelectProps
|
|
|
3057
3057
|
creatableHint?: string
|
|
3058
3058
|
/** Whether the select is disabled */
|
|
3059
3059
|
disabled?: boolean
|
|
3060
|
+
/** Max character length for the value (enforced when open and when creating) */
|
|
3061
|
+
maxLength?: number
|
|
3060
3062
|
}
|
|
3061
3063
|
|
|
3062
3064
|
const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
|
|
@@ -3070,6 +3072,7 @@ const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
|
|
|
3070
3072
|
placeholder = "Select an option",
|
|
3071
3073
|
creatableHint = "Type to create a custom option",
|
|
3072
3074
|
disabled = false,
|
|
3075
|
+
maxLength,
|
|
3073
3076
|
...props
|
|
3074
3077
|
},
|
|
3075
3078
|
ref
|
|
@@ -3119,11 +3122,12 @@ const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
|
|
|
3119
3122
|
const handleCreate = React.useCallback(() => {
|
|
3120
3123
|
const trimmed = search.trim()
|
|
3121
3124
|
if (trimmed) {
|
|
3122
|
-
|
|
3125
|
+
const value = maxLength != null ? trimmed.slice(0, maxLength) : trimmed
|
|
3126
|
+
onValueChange?.(value)
|
|
3123
3127
|
setOpen(false)
|
|
3124
3128
|
setSearch("")
|
|
3125
3129
|
}
|
|
3126
|
-
}, [search, onValueChange])
|
|
3130
|
+
}, [search, onValueChange, maxLength])
|
|
3127
3131
|
|
|
3128
3132
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
3129
3133
|
if (e.key === "Escape") {
|
|
@@ -3211,7 +3215,11 @@ const CreatableSelect = React.forwardRef<HTMLDivElement, CreatableSelectProps>(
|
|
|
3211
3215
|
ref={inputRef}
|
|
3212
3216
|
type="text"
|
|
3213
3217
|
value={search}
|
|
3214
|
-
onChange={(e) =>
|
|
3218
|
+
onChange={(e) => {
|
|
3219
|
+
const v = e.target.value
|
|
3220
|
+
setSearch(maxLength != null ? v.slice(0, maxLength) : v)
|
|
3221
|
+
}}
|
|
3222
|
+
maxLength={maxLength}
|
|
3215
3223
|
onKeyDown={handleKeyDown}
|
|
3216
3224
|
className="flex-1 min-w-0 bg-transparent outline-none text-base text-semantic-text-primary placeholder:text-semantic-text-muted"
|
|
3217
3225
|
placeholder={selectedLabel || placeholder}
|
|
@@ -3392,6 +3400,10 @@ export interface CreatableMultiSelectProps
|
|
|
3392
3400
|
creatableHint?: string
|
|
3393
3401
|
/** Helper text shown below the trigger */
|
|
3394
3402
|
helperText?: string
|
|
3403
|
+
/** Max number of items that can be selected (default: unlimited) */
|
|
3404
|
+
maxItems?: number
|
|
3405
|
+
/** Max character length per item when typing/creating (default: unlimited) */
|
|
3406
|
+
maxLengthPerItem?: number
|
|
3395
3407
|
}
|
|
3396
3408
|
|
|
3397
3409
|
const CreatableMultiSelect = React.forwardRef<
|
|
@@ -3409,6 +3421,8 @@ const CreatableMultiSelect = React.forwardRef<
|
|
|
3409
3421
|
state = "default",
|
|
3410
3422
|
creatableHint = "Type to create a custom option",
|
|
3411
3423
|
helperText,
|
|
3424
|
+
maxItems,
|
|
3425
|
+
maxLengthPerItem,
|
|
3412
3426
|
...props
|
|
3413
3427
|
},
|
|
3414
3428
|
ref
|
|
@@ -3423,12 +3437,18 @@ const CreatableMultiSelect = React.forwardRef<
|
|
|
3423
3437
|
const addValue = React.useCallback(
|
|
3424
3438
|
(val: string) => {
|
|
3425
3439
|
const trimmed = val.trim()
|
|
3426
|
-
if (trimmed
|
|
3427
|
-
|
|
3440
|
+
if (!trimmed || value.includes(trimmed)) return
|
|
3441
|
+
if (maxItems != null && value.length >= maxItems) return
|
|
3442
|
+
const toAdd =
|
|
3443
|
+
maxLengthPerItem != null
|
|
3444
|
+
? trimmed.slice(0, maxLengthPerItem)
|
|
3445
|
+
: trimmed
|
|
3446
|
+
if (toAdd) {
|
|
3447
|
+
onValueChange?.([...value, toAdd])
|
|
3428
3448
|
setInputValue("")
|
|
3429
3449
|
}
|
|
3430
3450
|
},
|
|
3431
|
-
[value, onValueChange]
|
|
3451
|
+
[value, onValueChange, maxItems, maxLengthPerItem]
|
|
3432
3452
|
)
|
|
3433
3453
|
|
|
3434
3454
|
const removeValue = React.useCallback(
|
|
@@ -3532,9 +3552,13 @@ const CreatableMultiSelect = React.forwardRef<
|
|
|
3532
3552
|
type="text"
|
|
3533
3553
|
value={inputValue}
|
|
3534
3554
|
onChange={(e) => {
|
|
3535
|
-
|
|
3555
|
+
const v = e.target.value
|
|
3556
|
+
setInputValue(
|
|
3557
|
+
maxLengthPerItem != null ? v.slice(0, maxLengthPerItem) : v
|
|
3558
|
+
)
|
|
3536
3559
|
if (!isOpen) setIsOpen(true)
|
|
3537
3560
|
}}
|
|
3561
|
+
maxLength={maxLengthPerItem}
|
|
3538
3562
|
onFocus={() => {
|
|
3539
3563
|
if (!disabled) setIsOpen(true)
|
|
3540
3564
|
}}
|
|
@@ -3558,18 +3582,14 @@ const CreatableMultiSelect = React.forwardRef<
|
|
|
3558
3582
|
{/* Dropdown panel */}
|
|
3559
3583
|
{isOpen && (
|
|
3560
3584
|
<div className="absolute z-[9999] top-full mt-1 w-full bg-semantic-bg-primary border border-semantic-border-layout rounded shadow-md animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-200">
|
|
3561
|
-
{/* Creatable hint \u2014
|
|
3585
|
+
{/* Creatable hint \u2014 Enter key */}
|
|
3562
3586
|
<div className="flex items-center justify-between px-4 py-2 border-b border-semantic-border-layout">
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
Press enter to add
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
{creatableHint}
|
|
3570
|
-
</span>
|
|
3571
|
-
)}
|
|
3572
|
-
<kbd className="inline-flex items-center gap-0.5 rounded border border-semantic-border-layout bg-semantic-bg-ui px-1.5 py-0.5 text-[10px] text-semantic-text-muted font-medium">
|
|
3587
|
+
<span className="text-sm text-semantic-text-muted">
|
|
3588
|
+
{canAddCustom
|
|
3589
|
+
? \`Press enter to add "\${inputValue.trim()}"\`
|
|
3590
|
+
: creatableHint}
|
|
3591
|
+
</span>
|
|
3592
|
+
<kbd className="inline-flex items-center gap-0.5 rounded border border-semantic-border-layout bg-semantic-bg-ui px-1.5 py-0.5 text-[10px] text-semantic-text-muted font-medium shrink-0">
|
|
3573
3593
|
Enter \u21B5
|
|
3574
3594
|
</kbd>
|
|
3575
3595
|
</div>
|
|
@@ -3597,14 +3617,31 @@ const CreatableMultiSelect = React.forwardRef<
|
|
|
3597
3617
|
</div>
|
|
3598
3618
|
)}
|
|
3599
3619
|
|
|
3600
|
-
{/* Helper
|
|
3601
|
-
{
|
|
3602
|
-
<div className="flex items-center gap-
|
|
3603
|
-
<
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3620
|
+
{/* Helper row below trigger: when maxLengthPerItem show dynamic hint + counter (Figma); else optional static helperText */}
|
|
3621
|
+
{maxLengthPerItem != null ? (
|
|
3622
|
+
<div className="flex items-center justify-between gap-2 mt-1.5">
|
|
3623
|
+
<div className="flex items-center gap-1.5 text-xs text-semantic-text-muted min-w-0">
|
|
3624
|
+
<Info className="size-3.5 shrink-0 text-semantic-text-muted" />
|
|
3625
|
+
<p className="m-0 truncate">
|
|
3626
|
+
{inputValue.trim()
|
|
3627
|
+
? \`Press Enter to add "\${inputValue.trim()}" \u21B5\`
|
|
3628
|
+
: creatableHint}
|
|
3629
|
+
</p>
|
|
3630
|
+
</div>
|
|
3631
|
+
<span className="text-sm text-semantic-text-muted shrink-0">
|
|
3632
|
+
{inputValue.length}/{maxLengthPerItem}
|
|
3633
|
+
</span>
|
|
3607
3634
|
</div>
|
|
3635
|
+
) : (
|
|
3636
|
+
helperText &&
|
|
3637
|
+
!isOpen && (
|
|
3638
|
+
<div className="flex items-center gap-1.5 mt-1.5">
|
|
3639
|
+
<Info className="size-[18px] shrink-0 text-semantic-text-muted" />
|
|
3640
|
+
<p className="m-0 text-sm text-semantic-text-muted">
|
|
3641
|
+
{helperText}
|
|
3642
|
+
</p>
|
|
3643
|
+
</div>
|
|
3644
|
+
)
|
|
3608
3645
|
)}
|
|
3609
3646
|
</div>
|
|
3610
3647
|
)
|
|
@@ -12833,7 +12870,7 @@ export type { BrandIconProps } from "./icon";
|
|
|
12833
12870
|
},
|
|
12834
12871
|
"bots": {
|
|
12835
12872
|
name: "bots",
|
|
12836
|
-
description: "AI Bot management components \u2014 BotList
|
|
12873
|
+
description: "AI Bot management components \u2014 BotList, BotListHeader, BotListSearch, BotListCreateCard, BotListGrid, BotCard, CreateBotModal",
|
|
12837
12874
|
category: "custom",
|
|
12838
12875
|
dependencies: [
|
|
12839
12876
|
"clsx",
|
|
@@ -12880,7 +12917,7 @@ function getTypeLabel(
|
|
|
12880
12917
|
* Set bot.type to "chatbot" or "voicebot"; no separate card components needed.
|
|
12881
12918
|
*/
|
|
12882
12919
|
export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
|
|
12883
|
-
({ bot, typeLabels, onEdit,
|
|
12920
|
+
({ bot, typeLabels, onEdit, onDelete, className, ...props }, ref) => {
|
|
12884
12921
|
const typeLabel = getTypeLabel(bot, typeLabels);
|
|
12885
12922
|
const isChatbot = bot.type === "chatbot";
|
|
12886
12923
|
|
|
@@ -13148,6 +13185,131 @@ export const CreateBotModal = React.forwardRef<
|
|
|
13148
13185
|
});
|
|
13149
13186
|
|
|
13150
13187
|
CreateBotModal.displayName = "CreateBotModal";
|
|
13188
|
+
`, prefix)
|
|
13189
|
+
},
|
|
13190
|
+
{
|
|
13191
|
+
name: "create-bot-flow.tsx",
|
|
13192
|
+
content: prefixTailwindClasses(`import * as React from "react";
|
|
13193
|
+
import { cn } from "../../../lib/utils";
|
|
13194
|
+
import { BotListCreateCard } from "./bot-list-create-card";
|
|
13195
|
+
import { BotListGrid } from "./bot-list-grid";
|
|
13196
|
+
import { CreateBotModal } from "./create-bot-modal";
|
|
13197
|
+
import type { CreateBotFlowProps } from "./types";
|
|
13198
|
+
|
|
13199
|
+
/**
|
|
13200
|
+
* Create bot flow: "Create new bot" card + Create Bot modal. No header (title/subtitle/search).
|
|
13201
|
+
* Use when you want the create-bot experience without the list header.
|
|
13202
|
+
*/
|
|
13203
|
+
export const CreateBotFlow = React.forwardRef<HTMLDivElement, CreateBotFlowProps>(
|
|
13204
|
+
(
|
|
13205
|
+
{
|
|
13206
|
+
createCardLabel = "Create new bot",
|
|
13207
|
+
onSubmit,
|
|
13208
|
+
className,
|
|
13209
|
+
...props
|
|
13210
|
+
},
|
|
13211
|
+
ref
|
|
13212
|
+
) => {
|
|
13213
|
+
const [modalOpen, setModalOpen] = React.useState(false);
|
|
13214
|
+
|
|
13215
|
+
return (
|
|
13216
|
+
<>
|
|
13217
|
+
<div
|
|
13218
|
+
ref={ref}
|
|
13219
|
+
className={cn(
|
|
13220
|
+
"flex flex-col w-full min-w-0 max-w-full overflow-x-hidden box-border",
|
|
13221
|
+
className
|
|
13222
|
+
)}
|
|
13223
|
+
{...props}
|
|
13224
|
+
>
|
|
13225
|
+
<BotListGrid>
|
|
13226
|
+
<BotListCreateCard
|
|
13227
|
+
label={createCardLabel}
|
|
13228
|
+
onClick={() => setModalOpen(true)}
|
|
13229
|
+
/>
|
|
13230
|
+
</BotListGrid>
|
|
13231
|
+
</div>
|
|
13232
|
+
<CreateBotModal
|
|
13233
|
+
open={modalOpen}
|
|
13234
|
+
onOpenChange={setModalOpen}
|
|
13235
|
+
onSubmit={(data) => {
|
|
13236
|
+
onSubmit?.(data);
|
|
13237
|
+
setModalOpen(false);
|
|
13238
|
+
}}
|
|
13239
|
+
/>
|
|
13240
|
+
</>
|
|
13241
|
+
);
|
|
13242
|
+
}
|
|
13243
|
+
);
|
|
13244
|
+
|
|
13245
|
+
CreateBotFlow.displayName = "CreateBotFlow";
|
|
13246
|
+
`, prefix)
|
|
13247
|
+
},
|
|
13248
|
+
{
|
|
13249
|
+
name: "edit-bot-flow.tsx",
|
|
13250
|
+
content: prefixTailwindClasses(`import * as React from "react";
|
|
13251
|
+
import { BotList } from "./bot-list";
|
|
13252
|
+
import type { Bot, EditBotFlowProps } from "./types";
|
|
13253
|
+
|
|
13254
|
+
/**
|
|
13255
|
+
* Edit bot flow: bot list + config view when Edit is clicked.
|
|
13256
|
+
* Use when you want the "Edit Bot \u2192 Config" experience; parent supplies config via renderConfig.
|
|
13257
|
+
*/
|
|
13258
|
+
export function EditBotFlow({
|
|
13259
|
+
bots,
|
|
13260
|
+
title = "AI Bot",
|
|
13261
|
+
subtitle = "Create & manage AI bots",
|
|
13262
|
+
searchPlaceholder = "Search bot...",
|
|
13263
|
+
createCardLabel = "Create new bot",
|
|
13264
|
+
typeLabels,
|
|
13265
|
+
onBotDelete,
|
|
13266
|
+
onCreateBotSubmit,
|
|
13267
|
+
onSearch,
|
|
13268
|
+
renderConfig,
|
|
13269
|
+
instructionText,
|
|
13270
|
+
className,
|
|
13271
|
+
}: EditBotFlowProps) {
|
|
13272
|
+
const [view, setView] = React.useState<"list" | "config">("list");
|
|
13273
|
+
const [editingBot, setEditingBot] = React.useState<Bot | null>(null);
|
|
13274
|
+
|
|
13275
|
+
const handleEdit = (botId: string) => {
|
|
13276
|
+
const bot = bots.find((b) => b.id === botId);
|
|
13277
|
+
if (bot) {
|
|
13278
|
+
setEditingBot(bot);
|
|
13279
|
+
setView("config");
|
|
13280
|
+
}
|
|
13281
|
+
};
|
|
13282
|
+
|
|
13283
|
+
const handleBack = () => {
|
|
13284
|
+
setView("list");
|
|
13285
|
+
setEditingBot(null);
|
|
13286
|
+
};
|
|
13287
|
+
|
|
13288
|
+
if (view === "config" && editingBot) {
|
|
13289
|
+
return <>{renderConfig(editingBot, handleBack)}</>;
|
|
13290
|
+
}
|
|
13291
|
+
|
|
13292
|
+
return (
|
|
13293
|
+
<>
|
|
13294
|
+
{instructionText != null ? (
|
|
13295
|
+
<div className="flex flex-col gap-2 p-6 pb-0">{instructionText}</div>
|
|
13296
|
+
) : null}
|
|
13297
|
+
<BotList
|
|
13298
|
+
bots={bots}
|
|
13299
|
+
title={title}
|
|
13300
|
+
subtitle={subtitle}
|
|
13301
|
+
searchPlaceholder={searchPlaceholder}
|
|
13302
|
+
createCardLabel={createCardLabel}
|
|
13303
|
+
typeLabels={typeLabels}
|
|
13304
|
+
onBotEdit={handleEdit}
|
|
13305
|
+
onBotDelete={onBotDelete}
|
|
13306
|
+
onCreateBotSubmit={onCreateBotSubmit}
|
|
13307
|
+
onSearch={onSearch}
|
|
13308
|
+
className={className}
|
|
13309
|
+
/>
|
|
13310
|
+
</>
|
|
13311
|
+
);
|
|
13312
|
+
}
|
|
13151
13313
|
`, prefix)
|
|
13152
13314
|
},
|
|
13153
13315
|
{
|
|
@@ -13170,7 +13332,6 @@ export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
|
|
|
13170
13332
|
onCreateBot,
|
|
13171
13333
|
onCreateBotSubmit,
|
|
13172
13334
|
onBotEdit,
|
|
13173
|
-
onBotPublish,
|
|
13174
13335
|
onBotDelete,
|
|
13175
13336
|
onSearch,
|
|
13176
13337
|
title = "AI Bot",
|
|
@@ -13190,43 +13351,69 @@ export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
|
|
|
13190
13351
|
onSearch?.(value);
|
|
13191
13352
|
};
|
|
13192
13353
|
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
|
|
13197
|
-
{...props}
|
|
13198
|
-
>
|
|
13199
|
-
{/* Page header: title, subtitle, and search */}
|
|
13200
|
-
<div className="flex flex-col gap-3 pb-4 mb-4 border-b border-semantic-border-layout sm:flex-row sm:items-center sm:justify-between sm:gap-4 sm:pb-5 sm:mb-6 min-w-0">
|
|
13201
|
-
<BotListHeader title={title} subtitle={subtitle} />
|
|
13202
|
-
<BotListSearch
|
|
13203
|
-
value={searchQuery}
|
|
13204
|
-
onSearch={handleSearch}
|
|
13205
|
-
placeholder={searchPlaceholder}
|
|
13206
|
-
/>
|
|
13207
|
-
</div>
|
|
13354
|
+
const handleCreateClick = () => {
|
|
13355
|
+
setCreateModalOpen(true);
|
|
13356
|
+
onCreateBot?.();
|
|
13357
|
+
};
|
|
13208
13358
|
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
|
|
13212
|
-
|
|
13213
|
-
|
|
13214
|
-
|
|
13215
|
-
|
|
13359
|
+
if (bots.length === 0) {
|
|
13360
|
+
return (
|
|
13361
|
+
<>
|
|
13362
|
+
<div
|
|
13363
|
+
ref={ref}
|
|
13364
|
+
className={cn(
|
|
13365
|
+
"flex flex-col w-full min-w-0 max-w-full overflow-x-hidden box-border",
|
|
13366
|
+
className
|
|
13367
|
+
)}
|
|
13368
|
+
{...props}
|
|
13369
|
+
>
|
|
13370
|
+
<BotListGrid>
|
|
13371
|
+
<BotListCreateCard
|
|
13372
|
+
label={createCardLabel}
|
|
13373
|
+
onClick={handleCreateClick}
|
|
13374
|
+
/>
|
|
13375
|
+
</BotListGrid>
|
|
13376
|
+
</div>
|
|
13377
|
+
<CreateBotModal
|
|
13378
|
+
open={createModalOpen}
|
|
13379
|
+
onOpenChange={setCreateModalOpen}
|
|
13380
|
+
onSubmit={(data) => {
|
|
13381
|
+
onCreateBotSubmit?.(data);
|
|
13382
|
+
setCreateModalOpen(false);
|
|
13216
13383
|
}}
|
|
13217
13384
|
/>
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
bot={bot}
|
|
13222
|
-
typeLabels={typeLabels}
|
|
13223
|
-
onEdit={onBotEdit}
|
|
13224
|
-
onPublish={onBotPublish}
|
|
13225
|
-
onDelete={onBotDelete}
|
|
13226
|
-
/>
|
|
13227
|
-
))}
|
|
13228
|
-
</BotListGrid>
|
|
13385
|
+
</>
|
|
13386
|
+
);
|
|
13387
|
+
}
|
|
13229
13388
|
|
|
13389
|
+
return (
|
|
13390
|
+
<>
|
|
13391
|
+
<div
|
|
13392
|
+
ref={ref}
|
|
13393
|
+
className={cn("flex flex-col w-full min-w-0 max-w-full overflow-x-hidden box-border", className)}
|
|
13394
|
+
{...props}
|
|
13395
|
+
>
|
|
13396
|
+
<div className="flex flex-col gap-3 pb-4 mb-4 border-b border-semantic-border-layout sm:flex-row sm:items-center sm:justify-between sm:gap-4 sm:pb-5 sm:mb-6 min-w-0">
|
|
13397
|
+
<BotListHeader title={title} subtitle={subtitle} />
|
|
13398
|
+
<BotListSearch
|
|
13399
|
+
value={searchQuery}
|
|
13400
|
+
onSearch={handleSearch}
|
|
13401
|
+
placeholder={searchPlaceholder}
|
|
13402
|
+
/>
|
|
13403
|
+
</div>
|
|
13404
|
+
<BotListGrid>
|
|
13405
|
+
<BotListCreateCard label={createCardLabel} onClick={handleCreateClick} />
|
|
13406
|
+
{bots.map((bot) => (
|
|
13407
|
+
<BotCard
|
|
13408
|
+
key={bot.id}
|
|
13409
|
+
bot={bot}
|
|
13410
|
+
typeLabels={typeLabels}
|
|
13411
|
+
onEdit={onBotEdit}
|
|
13412
|
+
onDelete={onBotDelete}
|
|
13413
|
+
/>
|
|
13414
|
+
))}
|
|
13415
|
+
</BotListGrid>
|
|
13416
|
+
</div>
|
|
13230
13417
|
<CreateBotModal
|
|
13231
13418
|
open={createModalOpen}
|
|
13232
13419
|
onOpenChange={setCreateModalOpen}
|
|
@@ -13235,7 +13422,7 @@ export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
|
|
|
13235
13422
|
setCreateModalOpen(false);
|
|
13236
13423
|
}}
|
|
13237
13424
|
/>
|
|
13238
|
-
|
|
13425
|
+
</>
|
|
13239
13426
|
);
|
|
13240
13427
|
}
|
|
13241
13428
|
);
|
|
@@ -13246,31 +13433,65 @@ BotList.displayName = "BotList";
|
|
|
13246
13433
|
{
|
|
13247
13434
|
name: "bot-list-header.tsx",
|
|
13248
13435
|
content: prefixTailwindClasses(`import * as React from "react";
|
|
13436
|
+
import { cva } from "class-variance-authority";
|
|
13249
13437
|
import { cn } from "../../../lib/utils";
|
|
13250
13438
|
import type { BotListHeaderProps } from "./types";
|
|
13251
13439
|
|
|
13440
|
+
const botListHeaderVariants = cva("min-w-0", {
|
|
13441
|
+
variants: {
|
|
13442
|
+
variant: {
|
|
13443
|
+
default:
|
|
13444
|
+
"flex flex-col gap-1.5 shrink",
|
|
13445
|
+
withSearch:
|
|
13446
|
+
"flex flex-col gap-3 pb-4 mb-4 border-b border-semantic-border-layout sm:flex-row sm:items-center sm:justify-between sm:gap-4 sm:pb-5 sm:mb-6 shrink",
|
|
13447
|
+
},
|
|
13448
|
+
},
|
|
13449
|
+
defaultVariants: {
|
|
13450
|
+
variant: "default",
|
|
13451
|
+
},
|
|
13452
|
+
});
|
|
13453
|
+
|
|
13252
13454
|
export const BotListHeader = React.forwardRef<HTMLDivElement, BotListHeaderProps>(
|
|
13253
|
-
(
|
|
13254
|
-
|
|
13255
|
-
|
|
13256
|
-
|
|
13257
|
-
|
|
13258
|
-
|
|
13259
|
-
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
|
|
13267
|
-
|
|
13268
|
-
|
|
13269
|
-
|
|
13270
|
-
|
|
13455
|
+
(
|
|
13456
|
+
{ title, subtitle, variant = "default", rightContent, className, ...props },
|
|
13457
|
+
ref
|
|
13458
|
+
) => {
|
|
13459
|
+
const rootClassName = cn(botListHeaderVariants({ variant }), className);
|
|
13460
|
+
const titleBlock = (
|
|
13461
|
+
<>
|
|
13462
|
+
{title != null && (
|
|
13463
|
+
<h1 className="m-0 text-base font-semibold text-semantic-text-primary tracking-[0.064px] break-words sm:text-lg">
|
|
13464
|
+
{title}
|
|
13465
|
+
</h1>
|
|
13466
|
+
)}
|
|
13467
|
+
{subtitle != null && (
|
|
13468
|
+
<p className="m-0 text-xs sm:text-sm text-semantic-text-muted tracking-[0.035px] break-words">
|
|
13469
|
+
{subtitle}
|
|
13470
|
+
</p>
|
|
13471
|
+
)}
|
|
13472
|
+
</>
|
|
13473
|
+
);
|
|
13474
|
+
|
|
13475
|
+
if (variant === "withSearch") {
|
|
13476
|
+
return (
|
|
13477
|
+
<div ref={ref} className={rootClassName} {...props}>
|
|
13478
|
+
<div className="flex flex-col gap-1.5 min-w-0 shrink">{titleBlock}</div>
|
|
13479
|
+
{rightContent}
|
|
13480
|
+
</div>
|
|
13481
|
+
);
|
|
13482
|
+
}
|
|
13483
|
+
|
|
13484
|
+
return (
|
|
13485
|
+
<div ref={ref} className={rootClassName} {...props}>
|
|
13486
|
+
{titleBlock}
|
|
13487
|
+
</div>
|
|
13488
|
+
);
|
|
13489
|
+
}
|
|
13271
13490
|
);
|
|
13272
13491
|
|
|
13273
13492
|
BotListHeader.displayName = "BotListHeader";
|
|
13493
|
+
|
|
13494
|
+
export { botListHeaderVariants };
|
|
13274
13495
|
`, prefix)
|
|
13275
13496
|
},
|
|
13276
13497
|
{
|
|
@@ -13517,8 +13738,6 @@ export interface BotCardProps
|
|
|
13517
13738
|
typeLabels?: Partial<Record<BotType, string>>;
|
|
13518
13739
|
/** Called when Edit action is selected */
|
|
13519
13740
|
onEdit?: (botId: string) => void;
|
|
13520
|
-
/** Called when Publish action is selected */
|
|
13521
|
-
onPublish?: (botId: string) => void;
|
|
13522
13741
|
/** Called when Delete action is selected */
|
|
13523
13742
|
onDelete?: (botId: string) => void;
|
|
13524
13743
|
}
|
|
@@ -13537,6 +13756,10 @@ export interface BotListHeaderProps
|
|
|
13537
13756
|
title?: string;
|
|
13538
13757
|
/** Optional subtitle below the title */
|
|
13539
13758
|
subtitle?: string;
|
|
13759
|
+
/** Layout variant: default (title + subtitle only) or withSearch (row with optional right slot) */
|
|
13760
|
+
variant?: "default" | "withSearch";
|
|
13761
|
+
/** Right-side content when variant is "withSearch" (e.g. BotListSearch) */
|
|
13762
|
+
rightContent?: React.ReactNode;
|
|
13540
13763
|
}
|
|
13541
13764
|
|
|
13542
13765
|
export interface BotListSearchProps
|
|
@@ -13574,6 +13797,43 @@ export interface BotListActionProps
|
|
|
13574
13797
|
align?: "start" | "center" | "end";
|
|
13575
13798
|
}
|
|
13576
13799
|
|
|
13800
|
+
/** Props for CreateBotFlow: create card + Create Bot modal (no header). */
|
|
13801
|
+
export interface CreateBotFlowProps
|
|
13802
|
+
extends Omit<React.HTMLAttributes<HTMLDivElement>, "children" | "onSubmit"> {
|
|
13803
|
+
/** Create new bot card label */
|
|
13804
|
+
createCardLabel?: string;
|
|
13805
|
+
/** Called when Create Bot modal is submitted with { name, type } */
|
|
13806
|
+
onSubmit?: (data: { name: string; type: BOT_TYPE }) => void;
|
|
13807
|
+
}
|
|
13808
|
+
|
|
13809
|
+
/** Props for EditBotFlow: bot list + config view when Edit is clicked. */
|
|
13810
|
+
export interface EditBotFlowProps {
|
|
13811
|
+
/** Bots to show in the list (e.g. first 2 for demo) */
|
|
13812
|
+
bots: Bot[];
|
|
13813
|
+
/** Page title */
|
|
13814
|
+
title?: string;
|
|
13815
|
+
/** Page subtitle */
|
|
13816
|
+
subtitle?: string;
|
|
13817
|
+
/** Search input placeholder */
|
|
13818
|
+
searchPlaceholder?: string;
|
|
13819
|
+
/** Create new bot card label */
|
|
13820
|
+
createCardLabel?: string;
|
|
13821
|
+
/** Override type badge labels */
|
|
13822
|
+
typeLabels?: Partial<Record<BotType, string>>;
|
|
13823
|
+
/** Called when Delete is selected on a bot */
|
|
13824
|
+
onBotDelete?: (botId: string) => void;
|
|
13825
|
+
/** Called when Create Bot modal is submitted */
|
|
13826
|
+
onCreateBotSubmit?: (data: { name: string; type: BOT_TYPE }) => void;
|
|
13827
|
+
/** Called when search query changes */
|
|
13828
|
+
onSearch?: (query: string) => void;
|
|
13829
|
+
/** Renders the config view for the given bot; call onBack() to return to list */
|
|
13830
|
+
renderConfig: (bot: Bot, onBack: () => void) => React.ReactNode;
|
|
13831
|
+
/** Optional instruction text above the list (e.g. "Click the \u22EE menu...") */
|
|
13832
|
+
instructionText?: React.ReactNode;
|
|
13833
|
+
/** Root className for the list wrapper */
|
|
13834
|
+
className?: string;
|
|
13835
|
+
}
|
|
13836
|
+
|
|
13577
13837
|
export interface BotListProps
|
|
13578
13838
|
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title" | "children"> {
|
|
13579
13839
|
/** List of bots to display */
|
|
@@ -13586,8 +13846,6 @@ export interface BotListProps
|
|
|
13586
13846
|
onCreateBotSubmit?: (data: { name: string; type: BOT_TYPE }) => void;
|
|
13587
13847
|
/** Called when user selects Edit on a bot (card click or menu) */
|
|
13588
13848
|
onBotEdit?: (botId: string) => void;
|
|
13589
|
-
/** Called when user selects Publish on a bot (menu; optional) */
|
|
13590
|
-
onBotPublish?: (botId: string) => void;
|
|
13591
13849
|
/** Called when user selects Delete on a bot */
|
|
13592
13850
|
onBotDelete?: (botId: string) => void;
|
|
13593
13851
|
/** Called when the search query changes */
|
|
@@ -13609,7 +13867,9 @@ export interface BotListProps
|
|
|
13609
13867
|
export type { BotCardProps } from "./types";
|
|
13610
13868
|
|
|
13611
13869
|
export { CreateBotModal } from "./create-bot-modal";
|
|
13612
|
-
export
|
|
13870
|
+
export { CreateBotFlow } from "./create-bot-flow";
|
|
13871
|
+
export { EditBotFlow } from "./edit-bot-flow";
|
|
13872
|
+
export type { CreateBotModalProps, CreateBotFlowProps, EditBotFlowProps } from "./types";
|
|
13613
13873
|
|
|
13614
13874
|
export { BotList } from "./bot-list";
|
|
13615
13875
|
export { BotListHeader } from "./bot-list-header";
|
|
@@ -15224,11 +15484,14 @@ function Field({
|
|
|
15224
15484
|
label,
|
|
15225
15485
|
required,
|
|
15226
15486
|
helperText,
|
|
15487
|
+
characterCount,
|
|
15227
15488
|
children,
|
|
15228
15489
|
}: {
|
|
15229
15490
|
label: string;
|
|
15230
15491
|
required?: boolean;
|
|
15231
15492
|
helperText?: string;
|
|
15493
|
+
/** e.g. { current: 0, max: 50 } to show "0/50" below right */
|
|
15494
|
+
characterCount?: { current: number; max: number };
|
|
15232
15495
|
children: React.ReactNode;
|
|
15233
15496
|
}) {
|
|
15234
15497
|
return (
|
|
@@ -15240,36 +15503,58 @@ function Field({
|
|
|
15240
15503
|
)}
|
|
15241
15504
|
</label>
|
|
15242
15505
|
{children}
|
|
15243
|
-
{helperText && (
|
|
15244
|
-
<div className="flex items-center
|
|
15245
|
-
|
|
15246
|
-
|
|
15506
|
+
{(helperText || characterCount) && (
|
|
15507
|
+
<div className="flex items-center justify-between gap-2">
|
|
15508
|
+
{helperText ? (
|
|
15509
|
+
<div className="flex items-center gap-1.5 text-xs text-semantic-text-muted min-w-0">
|
|
15510
|
+
<Info className="size-3.5 shrink-0" />
|
|
15511
|
+
<p className="m-0">{helperText}</p>
|
|
15512
|
+
</div>
|
|
15513
|
+
) : (
|
|
15514
|
+
<span />
|
|
15515
|
+
)}
|
|
15516
|
+
{characterCount != null && (
|
|
15517
|
+
<span className="text-sm text-semantic-text-muted shrink-0">
|
|
15518
|
+
{characterCount.current}/{characterCount.max}
|
|
15519
|
+
</span>
|
|
15520
|
+
)}
|
|
15247
15521
|
</div>
|
|
15248
15522
|
)}
|
|
15249
15523
|
</div>
|
|
15250
15524
|
);
|
|
15251
15525
|
}
|
|
15252
15526
|
|
|
15527
|
+
const BOT_NAME_MAX_LENGTH = 50;
|
|
15528
|
+
const PRIMARY_ROLE_MAX_LENGTH = 50;
|
|
15529
|
+
const TONE_MAX_ITEMS = 5;
|
|
15530
|
+
const TONE_MAX_LENGTH_PER_ITEM = 20;
|
|
15531
|
+
|
|
15253
15532
|
function StyledInput({
|
|
15254
15533
|
placeholder,
|
|
15255
15534
|
value,
|
|
15256
15535
|
onChange,
|
|
15257
15536
|
disabled,
|
|
15537
|
+
maxLength,
|
|
15258
15538
|
className,
|
|
15259
15539
|
}: {
|
|
15260
15540
|
placeholder?: string;
|
|
15261
15541
|
value?: string;
|
|
15262
15542
|
onChange?: (v: string) => void;
|
|
15263
15543
|
disabled?: boolean;
|
|
15544
|
+
maxLength?: number;
|
|
15264
15545
|
className?: string;
|
|
15265
15546
|
}) {
|
|
15266
15547
|
return (
|
|
15267
15548
|
<input
|
|
15268
15549
|
type="text"
|
|
15269
15550
|
value={value ?? ""}
|
|
15270
|
-
onChange={(e) =>
|
|
15551
|
+
onChange={(e) => {
|
|
15552
|
+
const v = e.target.value;
|
|
15553
|
+
onChange?.(maxLength != null ? v.slice(0, maxLength) : v);
|
|
15554
|
+
}}
|
|
15271
15555
|
placeholder={placeholder}
|
|
15272
15556
|
disabled={disabled}
|
|
15557
|
+
maxLength={maxLength}
|
|
15273
15558
|
className={cn(
|
|
15274
15559
|
"w-full h-[42px] px-4 text-base rounded border",
|
|
15275
15560
|
"border-semantic-border-input bg-semantic-bg-primary",
|
|
@@ -15365,34 +15650,52 @@ const BotIdentityCard = React.forwardRef<HTMLDivElement, BotIdentityCardProps>(
|
|
|
15365
15650
|
<Field
|
|
15366
15651
|
label="Bot Name & Identity"
|
|
15367
15652
|
helperText="This is the name the bot will use to refer to itself during conversations."
|
|
15653
|
+
characterCount={{
|
|
15654
|
+
current: (data.botName ?? "").length,
|
|
15655
|
+
max: BOT_NAME_MAX_LENGTH,
|
|
15656
|
+
}}
|
|
15368
15657
|
>
|
|
15369
15658
|
<StyledInput
|
|
15370
15659
|
placeholder="e.g., Rhea from CaratLane"
|
|
15371
15660
|
value={data.botName}
|
|
15372
15661
|
onChange={(v) => onChange({ botName: v })}
|
|
15373
15662
|
disabled={disabled}
|
|
15663
|
+
maxLength={BOT_NAME_MAX_LENGTH}
|
|
15374
15664
|
/>
|
|
15375
15665
|
</Field>
|
|
15376
15666
|
|
|
15377
|
-
<Field
|
|
15667
|
+
<Field
|
|
15668
|
+
label="Primary Role"
|
|
15669
|
+
characterCount={{
|
|
15670
|
+
current: (data.primaryRole ?? "").length,
|
|
15671
|
+
max: PRIMARY_ROLE_MAX_LENGTH,
|
|
15672
|
+
}}
|
|
15673
|
+
>
|
|
15378
15674
|
<CreatableSelect
|
|
15379
|
-
value={data.primaryRole
|
|
15380
|
-
onValueChange={(v) =>
|
|
15675
|
+
value={(data.primaryRole ?? "").slice(0, PRIMARY_ROLE_MAX_LENGTH)}
|
|
15676
|
+
onValueChange={(v) =>
|
|
15677
|
+
onChange({ primaryRole: (v ?? "").slice(0, PRIMARY_ROLE_MAX_LENGTH) })
|
|
15678
|
+
}
|
|
15381
15679
|
options={roleOptions}
|
|
15382
15680
|
placeholder="e.g., Customer Support Agent"
|
|
15383
15681
|
creatableHint="Type to create a custom role"
|
|
15384
15682
|
disabled={disabled}
|
|
15683
|
+
maxLength={PRIMARY_ROLE_MAX_LENGTH}
|
|
15385
15684
|
/>
|
|
15386
15685
|
</Field>
|
|
15387
15686
|
|
|
15388
15687
|
<Field label="Tone">
|
|
15389
15688
|
<CreatableMultiSelect
|
|
15390
|
-
value={Array.isArray(data.tone) ? data.tone : []}
|
|
15391
|
-
onValueChange={(v) =>
|
|
15689
|
+
value={(Array.isArray(data.tone) ? data.tone : []).slice(0, TONE_MAX_ITEMS)}
|
|
15690
|
+
onValueChange={(v) =>
|
|
15691
|
+
onChange({ tone: (v ?? []).slice(0, TONE_MAX_ITEMS) })
|
|
15692
|
+
}
|
|
15392
15693
|
options={toneOptions}
|
|
15393
15694
|
placeholder="Enter or select tone"
|
|
15394
|
-
creatableHint=
|
|
15695
|
+
creatableHint='Press Enter to add "Conversational" \u21B5'
|
|
15395
15696
|
disabled={disabled}
|
|
15697
|
+
maxItems={TONE_MAX_ITEMS}
|
|
15698
|
+
maxLengthPerItem={TONE_MAX_LENGTH_PER_ITEM}
|
|
15396
15699
|
/>
|
|
15397
15700
|
</Field>
|
|
15398
15701
|
|
|
@@ -15488,7 +15791,7 @@ export { BotIdentityCard };
|
|
|
15488
15791
|
{
|
|
15489
15792
|
name: "bot-behavior-card.tsx",
|
|
15490
15793
|
content: prefixTailwindClasses(`import * as React from "react";
|
|
15491
|
-
import { Plus } from "lucide-react";
|
|
15794
|
+
import { Plus, Info } from "lucide-react";
|
|
15492
15795
|
import { cn } from "../../../lib/utils";
|
|
15493
15796
|
import { tagVariants } from "../tag";
|
|
15494
15797
|
|
|
@@ -15507,7 +15810,7 @@ export interface BotBehaviorCardProps {
|
|
|
15507
15810
|
onSystemPromptBlur?: (value: string) => void;
|
|
15508
15811
|
/** Session variables shown as insertable chips */
|
|
15509
15812
|
sessionVariables?: string[];
|
|
15510
|
-
/** Maximum character length for the system prompt textarea (default:
|
|
15813
|
+
/** Maximum character length for the system prompt textarea (default: 5000, per Figma) */
|
|
15511
15814
|
maxLength?: number;
|
|
15512
15815
|
/** Disables all fields in the card (view mode) */
|
|
15513
15816
|
disabled?: boolean;
|
|
@@ -15564,7 +15867,7 @@ function StyledTextarea({
|
|
|
15564
15867
|
value?: string;
|
|
15565
15868
|
rows?: number;
|
|
15566
15869
|
onChange?: (v: string) => void;
|
|
15567
|
-
onBlur?: (
|
|
15870
|
+
onBlur?: (e: React.FocusEvent<HTMLTextAreaElement>) => void;
|
|
15568
15871
|
disabled?: boolean;
|
|
15569
15872
|
className?: string;
|
|
15570
15873
|
}) {
|
|
@@ -15573,7 +15876,7 @@ function StyledTextarea({
|
|
|
15573
15876
|
value={value ?? ""}
|
|
15574
15877
|
rows={rows}
|
|
15575
15878
|
onChange={(e) => onChange?.(e.target.value)}
|
|
15576
|
-
onBlur={
|
|
15879
|
+
onBlur={onBlur}
|
|
15577
15880
|
placeholder={placeholder}
|
|
15578
15881
|
disabled={disabled}
|
|
15579
15882
|
className={cn(
|
|
@@ -15598,7 +15901,7 @@ const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
|
|
|
15598
15901
|
onChange,
|
|
15599
15902
|
onSystemPromptBlur,
|
|
15600
15903
|
sessionVariables = DEFAULT_SESSION_VARIABLES,
|
|
15601
|
-
maxLength =
|
|
15904
|
+
maxLength = 5000,
|
|
15602
15905
|
disabled,
|
|
15603
15906
|
className,
|
|
15604
15907
|
},
|
|
@@ -15606,11 +15909,32 @@ const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
|
|
|
15606
15909
|
) => {
|
|
15607
15910
|
const prompt = data.systemPrompt ?? "";
|
|
15608
15911
|
const MAX = maxLength;
|
|
15912
|
+
const footerRef = React.useRef<HTMLDivElement>(null);
|
|
15913
|
+
/** Set on footer mousedown so blur does not trigger API when user clicked under the input (instruction/chips). */
|
|
15914
|
+
const footerClickInProgressRef = React.useRef(false);
|
|
15609
15915
|
|
|
15610
15916
|
const insertVariable = (variable: string) => {
|
|
15611
15917
|
onChange({ systemPrompt: prompt + variable });
|
|
15612
15918
|
};
|
|
15613
15919
|
|
|
15920
|
+
const handleSystemPromptBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
|
|
15921
|
+
if (!onSystemPromptBlur) return;
|
|
15922
|
+
const relatedTarget = e.relatedTarget as Node | null;
|
|
15923
|
+
const footerEl = footerRef.current;
|
|
15924
|
+
if (footerClickInProgressRef.current) {
|
|
15925
|
+
footerClickInProgressRef.current = false;
|
|
15926
|
+
return;
|
|
15927
|
+
}
|
|
15928
|
+
if (footerEl && relatedTarget && footerEl.contains(relatedTarget)) {
|
|
15929
|
+
return;
|
|
15930
|
+
}
|
|
15931
|
+
onSystemPromptBlur(e.target.value);
|
|
15932
|
+
};
|
|
15933
|
+
|
|
15934
|
+
const handleFooterMouseDown = () => {
|
|
15935
|
+
footerClickInProgressRef.current = true;
|
|
15936
|
+
};
|
|
15937
|
+
|
|
15614
15938
|
return (
|
|
15615
15939
|
<div ref={ref} className={className}>
|
|
15616
15940
|
<SectionCard title="How It Behaves">
|
|
@@ -15625,34 +15949,45 @@ const BotBehaviorCard = React.forwardRef<HTMLDivElement, BotBehaviorCardProps>(
|
|
|
15625
15949
|
onChange={(v) => {
|
|
15626
15950
|
if (v.length <= MAX) onChange({ systemPrompt: v });
|
|
15627
15951
|
}}
|
|
15628
|
-
onBlur={
|
|
15952
|
+
onBlur={handleSystemPromptBlur}
|
|
15629
15953
|
placeholder="You are a helpful assistant. Always start by greeting the user politely: 'Hello! Welcome. How can I assist you today?'"
|
|
15630
15954
|
disabled={disabled}
|
|
15631
|
-
className="pb-
|
|
15955
|
+
className="pb-10 pr-[4.5rem]"
|
|
15632
15956
|
/>
|
|
15633
|
-
<span
|
|
15957
|
+
<span
|
|
15958
|
+
className="absolute bottom-3 right-4 text-sm text-semantic-text-muted pointer-events-none"
|
|
15959
|
+
aria-live="polite"
|
|
15960
|
+
aria-label={\`\${prompt.length} of \${MAX} characters\`}
|
|
15961
|
+
>
|
|
15634
15962
|
{prompt.length}/{MAX}
|
|
15635
15963
|
</span>
|
|
15636
15964
|
</div>
|
|
15637
|
-
<
|
|
15638
|
-
|
|
15639
|
-
|
|
15640
|
-
|
|
15641
|
-
|
|
15642
|
-
|
|
15643
|
-
|
|
15644
|
-
|
|
15645
|
-
|
|
15646
|
-
|
|
15647
|
-
|
|
15648
|
-
|
|
15649
|
-
|
|
15650
|
-
|
|
15651
|
-
|
|
15652
|
-
|
|
15653
|
-
|
|
15654
|
-
|
|
15655
|
-
|
|
15965
|
+
<div
|
|
15966
|
+
ref={footerRef}
|
|
15967
|
+
className="flex flex-col gap-3"
|
|
15968
|
+
onMouseDown={handleFooterMouseDown}
|
|
15969
|
+
>
|
|
15970
|
+
<p className="m-0 flex items-center gap-1.5 text-sm text-semantic-text-muted">
|
|
15971
|
+
<Info className="size-4 shrink-0 text-semantic-text-muted" aria-hidden />
|
|
15972
|
+
Type {'{{'} to enable dropdown or use the below chips to input variables.
|
|
15973
|
+
</p>
|
|
15974
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
15975
|
+
<span className="text-sm text-semantic-text-secondary">
|
|
15976
|
+
Session variables:
|
|
15977
|
+
</span>
|
|
15978
|
+
{sessionVariables.map((v) => (
|
|
15979
|
+
<button
|
|
15980
|
+
key={v}
|
|
15981
|
+
type="button"
|
|
15982
|
+
onClick={() => insertVariable(v)}
|
|
15983
|
+
disabled={disabled}
|
|
15984
|
+
className={cn(tagVariants(), "gap-1.5 cursor-pointer hover:opacity-80 transition-opacity", disabled && "opacity-50 cursor-not-allowed")}
|
|
15985
|
+
>
|
|
15986
|
+
<Plus className="size-3 shrink-0" />
|
|
15987
|
+
{v}
|
|
15988
|
+
</button>
|
|
15989
|
+
))}
|
|
15990
|
+
</div>
|
|
15656
15991
|
</div>
|
|
15657
15992
|
</div>
|
|
15658
15993
|
</SectionCard>
|
|
@@ -16598,7 +16933,7 @@ export interface IvrBotConfigProps {
|
|
|
16598
16933
|
* Pass when your app fetches full function data after onEditFunction fires.
|
|
16599
16934
|
*/
|
|
16600
16935
|
functionEditData?: Partial<CreateFunctionData>;
|
|
16601
|
-
/** Max character length for the "How It Behaves" system prompt (default:
|
|
16936
|
+
/** Max character length for the "How It Behaves" system prompt (default: 5000, per Figma) */
|
|
16602
16937
|
systemPromptMaxLength?: number;
|
|
16603
16938
|
/** Called when the system prompt textarea loses focus */
|
|
16604
16939
|
onSystemPromptBlur?: (value: string) => void;
|