myoperator-ui 0.0.204-beta.1 → 0.0.204-beta.2
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 +426 -368
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1033,7 +1033,7 @@ import { cn } from "../../lib/utils";
|
|
|
1033
1033
|
* SelectTrigger variants matching TextField styling
|
|
1034
1034
|
*/
|
|
1035
1035
|
const selectTriggerVariants = cva(
|
|
1036
|
-
"flex h-10 w-full items-center justify-between rounded bg-semantic-bg-primary px-4 py-2.5 text-sm text-semantic-text-primary outline-none transition-all disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-[var(--color-neutral-50)] [&>span]:line-clamp-1",
|
|
1036
|
+
"flex h-10 w-full items-center justify-between rounded bg-semantic-bg-primary px-4 py-2.5 text-sm text-semantic-text-primary outline-none transition-all disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-[var(--color-neutral-50)] [&>span]:line-clamp-1 [&_[data-placeholder]]:text-semantic-text-placeholder",
|
|
1037
1037
|
{
|
|
1038
1038
|
variants: {
|
|
1039
1039
|
state: {
|
|
@@ -3334,14 +3334,14 @@ const DialogOverlay = React.forwardRef<
|
|
|
3334
3334
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
3335
3335
|
|
|
3336
3336
|
const dialogContentVariants = cva(
|
|
3337
|
-
"fixed left-[50%] top-[50%] z-[9999] grid translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg",
|
|
3337
|
+
"fixed left-[50%] top-[50%] z-[9999] grid translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-4 sm:p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg max-h-[calc(100vh-2rem)] overflow-y-auto [&::-webkit-scrollbar]:hidden [scrollbar-width:none] [&>*]:min-w-0",
|
|
3338
3338
|
{
|
|
3339
3339
|
variants: {
|
|
3340
3340
|
size: {
|
|
3341
|
-
sm: "w-
|
|
3342
|
-
default: "w-
|
|
3343
|
-
lg: "w-
|
|
3344
|
-
xl: "w-
|
|
3341
|
+
sm: "w-[calc(100%-2rem)] max-w-sm",
|
|
3342
|
+
default: "w-[calc(100%-2rem)] max-w-lg",
|
|
3343
|
+
lg: "w-[calc(100%-2rem)] max-w-2xl",
|
|
3344
|
+
xl: "w-[calc(100%-2rem)] max-w-4xl",
|
|
3345
3345
|
full: "w-[calc(100%-2rem)] h-[calc(100%-2rem)] max-w-none",
|
|
3346
3346
|
},
|
|
3347
3347
|
},
|
|
@@ -3418,7 +3418,7 @@ const DialogHeader = ({
|
|
|
3418
3418
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
3419
3419
|
<div
|
|
3420
3420
|
className={cn(
|
|
3421
|
-
"flex flex-col space-y-1.5 text-
|
|
3421
|
+
"flex flex-col space-y-1.5 text-left",
|
|
3422
3422
|
className
|
|
3423
3423
|
)}
|
|
3424
3424
|
{...props}
|
|
@@ -12030,8 +12030,10 @@ export const BotCard = React.forwardRef<HTMLDivElement, BotCardProps>(
|
|
|
12030
12030
|
Last Published
|
|
12031
12031
|
</span>
|
|
12032
12032
|
{bot.lastPublishedBy && bot.lastPublishedDate ? (
|
|
12033
|
-
<p className="m-0 text-sm text-semantic-text-muted">
|
|
12034
|
-
{bot.lastPublishedBy}
|
|
12033
|
+
<p className="m-0 text-sm text-semantic-text-muted break-words">
|
|
12034
|
+
<span className="inline-block">{bot.lastPublishedBy}</span>
|
|
12035
|
+
<span className="mx-1">|</span>
|
|
12036
|
+
<span className="inline-block">{bot.lastPublishedDate}</span>
|
|
12035
12037
|
</p>
|
|
12036
12038
|
) : (
|
|
12037
12039
|
<p className="m-0 text-sm text-semantic-text-muted">\u2014</p>
|
|
@@ -12136,7 +12138,7 @@ export const CreateBotModal = React.forwardRef<
|
|
|
12136
12138
|
<span className="text-sm font-semibold text-semantic-text-secondary tracking-[0.014px]">
|
|
12137
12139
|
Select Bot Type
|
|
12138
12140
|
</span>
|
|
12139
|
-
<div className="flex gap-3">
|
|
12141
|
+
<div className="flex flex-col sm:flex-row gap-3">
|
|
12140
12142
|
{BOT_TYPE_OPTIONS.map(({ id, label, description }) => {
|
|
12141
12143
|
const isSelected = selectedType === id;
|
|
12142
12144
|
return (
|
|
@@ -12145,7 +12147,7 @@ export const CreateBotModal = React.forwardRef<
|
|
|
12145
12147
|
type="button"
|
|
12146
12148
|
onClick={() => setSelectedType(id)}
|
|
12147
12149
|
className={cn(
|
|
12148
|
-
"flex flex-col gap-2.5 p-3 rounded-lg border text-left flex-1 h-[134px] justify-center",
|
|
12150
|
+
"flex flex-col gap-2.5 p-3 rounded-lg border text-left flex-1 sm:h-[134px] justify-center",
|
|
12149
12151
|
"transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-semantic-border-focus",
|
|
12150
12152
|
isSelected
|
|
12151
12153
|
? "bg-semantic-info-surface border-semantic-border-focus shadow-sm"
|
|
@@ -12247,7 +12249,7 @@ export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
|
|
|
12247
12249
|
return (
|
|
12248
12250
|
<div ref={ref} className={cn("flex flex-col w-full", className)}>
|
|
12249
12251
|
{/* Page header */}
|
|
12250
|
-
<div className="flex items-center justify-between pb-5 mb-6 border-b border-semantic-border-layout">
|
|
12252
|
+
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 pb-5 mb-6 border-b border-semantic-border-layout">
|
|
12251
12253
|
<div className="flex flex-col gap-1.5">
|
|
12252
12254
|
<h1 className="m-0 text-base font-semibold text-semantic-text-primary tracking-[0.064px]">
|
|
12253
12255
|
{title}
|
|
@@ -12258,20 +12260,20 @@ export const BotList = React.forwardRef<HTMLDivElement, BotListProps>(
|
|
|
12258
12260
|
</div>
|
|
12259
12261
|
|
|
12260
12262
|
{/* Search bar */}
|
|
12261
|
-
<div className="flex items-center gap-2 h-10 px-2.5 border border-semantic-border-input rounded bg-semantic-bg-primary hover:border-semantic-border-input-focus focus-within:border-semantic-border-input-focus focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]">
|
|
12263
|
+
<div className="flex items-center gap-2 h-10 px-2.5 border border-semantic-border-input rounded bg-semantic-bg-primary hover:border-semantic-border-input-focus focus-within:border-semantic-border-input-focus focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)] w-full sm:w-auto">
|
|
12262
12264
|
<Search className="size-[14px] text-semantic-text-muted shrink-0" />
|
|
12263
12265
|
<input
|
|
12264
12266
|
type="text"
|
|
12265
12267
|
value={searchQuery}
|
|
12266
12268
|
onChange={(e) => handleSearch(e.target.value)}
|
|
12267
12269
|
placeholder="Search bot..."
|
|
12268
|
-
className="text-sm text-semantic-text-primary placeholder:text-semantic-text-muted bg-transparent outline-none w-[180px]"
|
|
12270
|
+
className="text-sm text-semantic-text-primary placeholder:text-semantic-text-muted bg-transparent outline-none w-full sm:w-[180px]"
|
|
12269
12271
|
/>
|
|
12270
12272
|
</div>
|
|
12271
12273
|
</div>
|
|
12272
12274
|
|
|
12273
12275
|
{/* Bot grid */}
|
|
12274
|
-
<div className="grid grid-cols-3 gap-6">
|
|
12276
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
12275
12277
|
{/* Create new bot card */}
|
|
12276
12278
|
<button
|
|
12277
12279
|
type="button"
|
|
@@ -12406,7 +12408,6 @@ export type { BotListProps, Bot, BotType } from "./types";
|
|
|
12406
12408
|
content: prefixTailwindClasses(`import * as React from "react";
|
|
12407
12409
|
import {
|
|
12408
12410
|
ChevronLeft,
|
|
12409
|
-
ChevronDown,
|
|
12410
12411
|
Plus,
|
|
12411
12412
|
Download,
|
|
12412
12413
|
Trash2,
|
|
@@ -12430,6 +12431,20 @@ import {
|
|
|
12430
12431
|
AccordionTrigger,
|
|
12431
12432
|
AccordionContent,
|
|
12432
12433
|
} from "../accordion";
|
|
12434
|
+
import {
|
|
12435
|
+
Select,
|
|
12436
|
+
SelectTrigger,
|
|
12437
|
+
SelectValue,
|
|
12438
|
+
SelectContent,
|
|
12439
|
+
SelectItem,
|
|
12440
|
+
} from "../select";
|
|
12441
|
+
import {
|
|
12442
|
+
Tooltip,
|
|
12443
|
+
TooltipTrigger,
|
|
12444
|
+
TooltipContent,
|
|
12445
|
+
TooltipArrow,
|
|
12446
|
+
TooltipProvider,
|
|
12447
|
+
} from "../tooltip";
|
|
12433
12448
|
import { CreateFunctionModal } from "./create-function-modal";
|
|
12434
12449
|
import type {
|
|
12435
12450
|
IvrBotConfigProps,
|
|
@@ -12458,13 +12473,13 @@ function SectionCard({
|
|
|
12458
12473
|
className
|
|
12459
12474
|
)}
|
|
12460
12475
|
>
|
|
12461
|
-
<div className="flex items-center justify-between px-6 py-4 border-b border-semantic-border-layout">
|
|
12476
|
+
<div className="flex items-center justify-between px-4 sm:px-6 py-4 border-b border-semantic-border-layout">
|
|
12462
12477
|
<h2 className="m-0 text-base font-semibold text-semantic-text-primary">
|
|
12463
12478
|
{title}
|
|
12464
12479
|
</h2>
|
|
12465
12480
|
{action}
|
|
12466
12481
|
</div>
|
|
12467
|
-
<div className="px-6 py-5">{children}</div>
|
|
12482
|
+
<div className="px-4 sm:px-6 py-5">{children}</div>
|
|
12468
12483
|
</div>
|
|
12469
12484
|
);
|
|
12470
12485
|
}
|
|
@@ -12521,7 +12536,7 @@ function StyledInput({
|
|
|
12521
12536
|
className={cn(
|
|
12522
12537
|
"w-full h-10 px-4 text-sm rounded border",
|
|
12523
12538
|
"border-semantic-border-input bg-semantic-bg-primary",
|
|
12524
|
-
"text-semantic-text-primary placeholder:text-semantic-text-
|
|
12539
|
+
"text-semantic-text-primary placeholder:text-semantic-text-placeholder",
|
|
12525
12540
|
"outline-none hover:border-semantic-border-input-focus",
|
|
12526
12541
|
"focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
|
|
12527
12542
|
className
|
|
@@ -12553,7 +12568,7 @@ function StyledTextarea({
|
|
|
12553
12568
|
className={cn(
|
|
12554
12569
|
"w-full px-4 py-2.5 text-sm rounded border resize-none",
|
|
12555
12570
|
"border-semantic-border-input bg-semantic-bg-primary",
|
|
12556
|
-
"text-semantic-text-primary placeholder:text-semantic-text-
|
|
12571
|
+
"text-semantic-text-primary placeholder:text-semantic-text-placeholder",
|
|
12557
12572
|
"outline-none hover:border-semantic-border-input-focus",
|
|
12558
12573
|
"focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
|
|
12559
12574
|
className
|
|
@@ -12562,56 +12577,6 @@ function StyledTextarea({
|
|
|
12562
12577
|
);
|
|
12563
12578
|
}
|
|
12564
12579
|
|
|
12565
|
-
// \u2500\u2500\u2500 Styled Select \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
12566
|
-
function StyledSelect({
|
|
12567
|
-
placeholder,
|
|
12568
|
-
value,
|
|
12569
|
-
onChange,
|
|
12570
|
-
options,
|
|
12571
|
-
disabled,
|
|
12572
|
-
className,
|
|
12573
|
-
}: {
|
|
12574
|
-
placeholder?: string;
|
|
12575
|
-
value?: string;
|
|
12576
|
-
onChange?: (v: string) => void;
|
|
12577
|
-
options?: { label: string; value: string }[];
|
|
12578
|
-
disabled?: boolean;
|
|
12579
|
-
className?: string;
|
|
12580
|
-
}) {
|
|
12581
|
-
return (
|
|
12582
|
-
<div className={cn("relative w-full", className)}>
|
|
12583
|
-
<select
|
|
12584
|
-
value={value ?? ""}
|
|
12585
|
-
onChange={(e) => onChange?.(e.target.value)}
|
|
12586
|
-
disabled={disabled}
|
|
12587
|
-
className={cn(
|
|
12588
|
-
"w-full h-10 pl-4 pr-10 text-sm rounded border appearance-none cursor-pointer",
|
|
12589
|
-
"border-semantic-border-input bg-semantic-bg-primary",
|
|
12590
|
-
value ? "text-semantic-text-primary" : "text-semantic-text-muted",
|
|
12591
|
-
"outline-none hover:border-semantic-border-input-focus",
|
|
12592
|
-
"focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
|
|
12593
|
-
"disabled:opacity-50 disabled:cursor-not-allowed"
|
|
12594
|
-
)}
|
|
12595
|
-
>
|
|
12596
|
-
{placeholder && (
|
|
12597
|
-
<option value="" disabled>
|
|
12598
|
-
{placeholder}
|
|
12599
|
-
</option>
|
|
12600
|
-
)}
|
|
12601
|
-
{options?.map((opt) => (
|
|
12602
|
-
<option key={opt.value} value={opt.value}>
|
|
12603
|
-
{opt.label}
|
|
12604
|
-
</option>
|
|
12605
|
-
))}
|
|
12606
|
-
</select>
|
|
12607
|
-
<ChevronDown
|
|
12608
|
-
className="absolute right-3 top-1/2 -translate-y-1/2 size-4 text-semantic-text-muted pointer-events-none shrink-0"
|
|
12609
|
-
aria-hidden="true"
|
|
12610
|
-
/>
|
|
12611
|
-
</div>
|
|
12612
|
-
);
|
|
12613
|
-
}
|
|
12614
|
-
|
|
12615
12580
|
// \u2500\u2500\u2500 Who The Bot Is \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
12616
12581
|
function WhoTheBotIs({
|
|
12617
12582
|
data,
|
|
@@ -12635,54 +12600,74 @@ function WhoTheBotIs({
|
|
|
12635
12600
|
</Field>
|
|
12636
12601
|
|
|
12637
12602
|
<Field label="Primary Role">
|
|
12638
|
-
<
|
|
12639
|
-
|
|
12640
|
-
|
|
12641
|
-
|
|
12642
|
-
|
|
12603
|
+
<Select
|
|
12604
|
+
value={data.primaryRole || undefined}
|
|
12605
|
+
onValueChange={(v) => onChange({ primaryRole: v })}
|
|
12606
|
+
>
|
|
12607
|
+
<SelectTrigger>
|
|
12608
|
+
<SelectValue placeholder="e.g., Customer Support Agent" />
|
|
12609
|
+
</SelectTrigger>
|
|
12610
|
+
<SelectContent>
|
|
12611
|
+
<SelectItem value="customer-support-agent">Customer Support Agent</SelectItem>
|
|
12612
|
+
<SelectItem value="sales-representative">Sales Representative</SelectItem>
|
|
12613
|
+
<SelectItem value="technical-support">Technical Support</SelectItem>
|
|
12614
|
+
<SelectItem value="billing-support">Billing Support</SelectItem>
|
|
12615
|
+
<SelectItem value="general-inquiries">General Inquiries</SelectItem>
|
|
12616
|
+
</SelectContent>
|
|
12617
|
+
</Select>
|
|
12643
12618
|
</Field>
|
|
12644
12619
|
|
|
12645
12620
|
<Field label="Tone">
|
|
12646
|
-
<
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
</
|
|
12621
|
+
<Select
|
|
12622
|
+
value={data.tone || undefined}
|
|
12623
|
+
onValueChange={(v) => onChange({ tone: v })}
|
|
12624
|
+
>
|
|
12625
|
+
<SelectTrigger>
|
|
12626
|
+
<SelectValue placeholder="Enter or select tone" />
|
|
12627
|
+
</SelectTrigger>
|
|
12628
|
+
<SelectContent>
|
|
12629
|
+
<SelectItem value="conversational">Conversational</SelectItem>
|
|
12630
|
+
<SelectItem value="professional">Professional</SelectItem>
|
|
12631
|
+
<SelectItem value="friendly">Friendly</SelectItem>
|
|
12632
|
+
<SelectItem value="formal">Formal</SelectItem>
|
|
12633
|
+
</SelectContent>
|
|
12634
|
+
</Select>
|
|
12635
|
+
<div className="flex items-center gap-1.5 text-xs text-semantic-text-muted">
|
|
12636
|
+
<Info className="size-3.5 shrink-0" />
|
|
12637
|
+
<p className="m-0">Press Enter to add “Conversational”</p>
|
|
12638
|
+
</div>
|
|
12660
12639
|
</Field>
|
|
12661
12640
|
|
|
12662
|
-
<div className="grid grid-cols-2 gap-4">
|
|
12641
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
12663
12642
|
<Field label="How It Sounds">
|
|
12664
|
-
<
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12670
|
-
|
|
12671
|
-
|
|
12672
|
-
|
|
12673
|
-
|
|
12643
|
+
<Select
|
|
12644
|
+
value={data.voice || undefined}
|
|
12645
|
+
onValueChange={(v) => onChange({ voice: v })}
|
|
12646
|
+
>
|
|
12647
|
+
<SelectTrigger>
|
|
12648
|
+
<SelectValue placeholder="Rhea - Female" />
|
|
12649
|
+
</SelectTrigger>
|
|
12650
|
+
<SelectContent>
|
|
12651
|
+
<SelectItem value="rhea-female">Rhea - Female</SelectItem>
|
|
12652
|
+
<SelectItem value="james-male">James - Male</SelectItem>
|
|
12653
|
+
<SelectItem value="aria-female">Aria - Female</SelectItem>
|
|
12654
|
+
</SelectContent>
|
|
12655
|
+
</Select>
|
|
12674
12656
|
</Field>
|
|
12675
12657
|
<Field label="What Language It Speaks">
|
|
12676
|
-
<
|
|
12677
|
-
|
|
12678
|
-
|
|
12679
|
-
|
|
12680
|
-
|
|
12681
|
-
|
|
12682
|
-
|
|
12683
|
-
|
|
12684
|
-
|
|
12685
|
-
|
|
12658
|
+
<Select
|
|
12659
|
+
value={data.language || undefined}
|
|
12660
|
+
onValueChange={(v) => onChange({ language: v })}
|
|
12661
|
+
>
|
|
12662
|
+
<SelectTrigger>
|
|
12663
|
+
<SelectValue placeholder="Select Language Mode" />
|
|
12664
|
+
</SelectTrigger>
|
|
12665
|
+
<SelectContent>
|
|
12666
|
+
<SelectItem value="en-in">English (India)</SelectItem>
|
|
12667
|
+
<SelectItem value="en-us">English (US)</SelectItem>
|
|
12668
|
+
<SelectItem value="hi-in">Hindi</SelectItem>
|
|
12669
|
+
</SelectContent>
|
|
12670
|
+
</Select>
|
|
12686
12671
|
</Field>
|
|
12687
12672
|
</div>
|
|
12688
12673
|
</div>
|
|
@@ -12694,7 +12679,9 @@ function WhoTheBotIs({
|
|
|
12694
12679
|
const SESSION_VARIABLES = [
|
|
12695
12680
|
"{{Caller number}}",
|
|
12696
12681
|
"{{Time}}",
|
|
12682
|
+
"{{Morning/Afternoon/Evening}}",
|
|
12697
12683
|
"{{Contact Details}}",
|
|
12684
|
+
"{{DID}}",
|
|
12698
12685
|
];
|
|
12699
12686
|
|
|
12700
12687
|
function HowItBehaves({
|
|
@@ -12713,11 +12700,12 @@ function HowItBehaves({
|
|
|
12713
12700
|
|
|
12714
12701
|
return (
|
|
12715
12702
|
<SectionCard title="How It Behaves">
|
|
12716
|
-
<div className="flex flex-col gap-
|
|
12717
|
-
|
|
12718
|
-
|
|
12719
|
-
|
|
12720
|
-
|
|
12703
|
+
<div className="flex flex-col gap-6">
|
|
12704
|
+
{/* Prompt editor group */}
|
|
12705
|
+
<div className="flex flex-col gap-1.5">
|
|
12706
|
+
<p className="m-0 text-sm font-semibold text-semantic-text-secondary">
|
|
12707
|
+
Define workflows, conditions and handover logic (System prompt)
|
|
12708
|
+
</p>
|
|
12721
12709
|
<StyledTextarea
|
|
12722
12710
|
value={prompt}
|
|
12723
12711
|
rows={6}
|
|
@@ -12725,17 +12713,22 @@ function HowItBehaves({
|
|
|
12725
12713
|
if (v.length <= MAX) onChange({ systemPrompt: v });
|
|
12726
12714
|
}}
|
|
12727
12715
|
placeholder="You are a helpful assistant. Always start by greeting the user politely: 'Hello! Welcome. How can I assist you today?'"
|
|
12728
|
-
className="pb-8"
|
|
12729
12716
|
/>
|
|
12730
|
-
|
|
12731
|
-
|
|
12732
|
-
|
|
12717
|
+
{/* Helper row: info + hint text on left, counter on right */}
|
|
12718
|
+
<div className="flex items-center justify-between gap-2">
|
|
12719
|
+
<div className="flex items-center gap-1.5 text-xs text-semantic-text-muted">
|
|
12720
|
+
<Info className="size-3.5 shrink-0" />
|
|
12721
|
+
<p className="m-0">Type {"{{"} to enable dropdown or use the below chips to input variables.</p>
|
|
12722
|
+
</div>
|
|
12723
|
+
<span className="shrink-0 text-xs text-semantic-text-muted whitespace-nowrap">
|
|
12724
|
+
{prompt.length}/{MAX}
|
|
12725
|
+
</span>
|
|
12726
|
+
</div>
|
|
12733
12727
|
</div>
|
|
12734
|
-
|
|
12735
|
-
|
|
12736
|
-
</p>
|
|
12728
|
+
|
|
12729
|
+
{/* Session variables row */}
|
|
12737
12730
|
<div className="flex flex-wrap items-center gap-2">
|
|
12738
|
-
<span className="text-xs text-semantic-text-
|
|
12731
|
+
<span className="text-xs font-semibold text-semantic-text-muted">
|
|
12739
12732
|
Session variables:
|
|
12740
12733
|
</span>
|
|
12741
12734
|
{SESSION_VARIABLES.map((v) => (
|
|
@@ -12743,9 +12736,12 @@ function HowItBehaves({
|
|
|
12743
12736
|
key={v}
|
|
12744
12737
|
type="button"
|
|
12745
12738
|
onClick={() => insertVariable(v)}
|
|
12746
|
-
className={cn(
|
|
12739
|
+
className={cn(
|
|
12740
|
+
tagVariants({ size: "sm" }),
|
|
12741
|
+
"gap-2.5 cursor-pointer hover:opacity-80 transition-opacity"
|
|
12742
|
+
)}
|
|
12747
12743
|
>
|
|
12748
|
-
<Plus className="size-
|
|
12744
|
+
<Plus className="size-2.5 shrink-0" />
|
|
12749
12745
|
{v}
|
|
12750
12746
|
</button>
|
|
12751
12747
|
))}
|
|
@@ -12767,14 +12763,24 @@ function FallbackPromptsAccordion({
|
|
|
12767
12763
|
<div className="bg-semantic-bg-primary border border-semantic-border-layout rounded-lg overflow-hidden">
|
|
12768
12764
|
<Accordion type="single">
|
|
12769
12765
|
<AccordionItem value="fallback">
|
|
12770
|
-
<AccordionTrigger className="px-6 py-5 border-b border-semantic-border-layout hover:no-underline">
|
|
12766
|
+
<AccordionTrigger className="px-4 sm:px-6 py-5 border-b border-semantic-border-layout hover:no-underline">
|
|
12771
12767
|
<span className="flex items-center gap-1.5 text-base font-semibold text-semantic-text-primary">
|
|
12772
12768
|
Fallback Prompts
|
|
12773
|
-
<
|
|
12769
|
+
<Tooltip>
|
|
12770
|
+
<TooltipTrigger asChild>
|
|
12771
|
+
<span className="inline-flex cursor-default">
|
|
12772
|
+
<Info className="size-3.5 text-semantic-text-muted shrink-0" />
|
|
12773
|
+
</span>
|
|
12774
|
+
</TooltipTrigger>
|
|
12775
|
+
<TooltipContent>
|
|
12776
|
+
<p className="m-0">Configure what the bot says when agents are busy or extensions are unavailable.</p>
|
|
12777
|
+
<TooltipArrow />
|
|
12778
|
+
</TooltipContent>
|
|
12779
|
+
</Tooltip>
|
|
12774
12780
|
</span>
|
|
12775
12781
|
</AccordionTrigger>
|
|
12776
12782
|
<AccordionContent>
|
|
12777
|
-
<div className="px-6 pt-6 pb-2 flex flex-col gap-6">
|
|
12783
|
+
<div className="px-4 sm:px-6 pt-6 pb-2 flex flex-col gap-6">
|
|
12778
12784
|
<Field label="Agent Busy Prompt">
|
|
12779
12785
|
<StyledTextarea
|
|
12780
12786
|
value={data.agentBusyPrompt ?? ""}
|
|
@@ -12886,7 +12892,7 @@ function FileUploadModal({
|
|
|
12886
12892
|
<DialogContent
|
|
12887
12893
|
size="default"
|
|
12888
12894
|
hideCloseButton
|
|
12889
|
-
className="max-w-[660px] rounded-xl
|
|
12895
|
+
className="max-w-[660px] rounded-xl gap-0"
|
|
12890
12896
|
>
|
|
12891
12897
|
{/* Header */}
|
|
12892
12898
|
<div className="flex items-center justify-between mb-6">
|
|
@@ -12905,7 +12911,7 @@ function FileUploadModal({
|
|
|
12905
12911
|
</div>
|
|
12906
12912
|
|
|
12907
12913
|
{/* Body */}
|
|
12908
|
-
<div className="flex flex-col gap-4 items-end w-full">
|
|
12914
|
+
<div className="flex flex-col gap-4 items-center sm:items-end w-full">
|
|
12909
12915
|
{/* Download sample file */}
|
|
12910
12916
|
<button
|
|
12911
12917
|
type="button"
|
|
@@ -12925,7 +12931,7 @@ function FileUploadModal({
|
|
|
12925
12931
|
}}
|
|
12926
12932
|
onDragOver={(e) => e.preventDefault()}
|
|
12927
12933
|
>
|
|
12928
|
-
<div className="flex items-center gap-4">
|
|
12934
|
+
<div className="flex flex-col items-center sm:flex-row sm:items-center gap-3 sm:gap-4">
|
|
12929
12935
|
<button
|
|
12930
12936
|
type="button"
|
|
12931
12937
|
onClick={() => fileInputRef.current?.click()}
|
|
@@ -12933,7 +12939,7 @@ function FileUploadModal({
|
|
|
12933
12939
|
>
|
|
12934
12940
|
Upload from device
|
|
12935
12941
|
</button>
|
|
12936
|
-
<div className="flex flex-col gap-1">
|
|
12942
|
+
<div className="flex flex-col gap-1 text-center sm:text-left">
|
|
12937
12943
|
<p className="m-0 text-sm text-semantic-text-secondary tracking-[0.035px]">
|
|
12938
12944
|
or drag and drop file here
|
|
12939
12945
|
</p>
|
|
@@ -13021,11 +13027,11 @@ function FileUploadModal({
|
|
|
13021
13027
|
</div>
|
|
13022
13028
|
|
|
13023
13029
|
{/* Footer */}
|
|
13024
|
-
<div className="flex items-center justify-
|
|
13025
|
-
<Button variant="outline" onClick={handleClose}>
|
|
13030
|
+
<div className="flex items-center justify-between gap-2 mt-6">
|
|
13031
|
+
<Button variant="outline" onClick={handleClose} className="flex-1 sm:flex-none sm:w-auto">
|
|
13026
13032
|
Cancel
|
|
13027
13033
|
</Button>
|
|
13028
|
-
<Button onClick={handleSave}>
|
|
13034
|
+
<Button onClick={handleSave} className="flex-1 sm:flex-none sm:w-auto">
|
|
13029
13035
|
Save
|
|
13030
13036
|
</Button>
|
|
13031
13037
|
</div>
|
|
@@ -13062,12 +13068,22 @@ function KnowledgeBase({
|
|
|
13062
13068
|
<>
|
|
13063
13069
|
<div className="bg-semantic-bg-primary border border-semantic-border-layout rounded-lg overflow-hidden">
|
|
13064
13070
|
{/* Header */}
|
|
13065
|
-
<div className="flex items-center justify-between px-6 py-4 border-b border-semantic-border-layout">
|
|
13071
|
+
<div className="flex items-center justify-between px-4 sm:px-6 py-4 border-b border-semantic-border-layout">
|
|
13066
13072
|
<div className="flex items-center gap-1.5">
|
|
13067
13073
|
<h2 className="m-0 text-base font-semibold text-semantic-text-primary">
|
|
13068
13074
|
Knowledge Base
|
|
13069
13075
|
</h2>
|
|
13070
|
-
<
|
|
13076
|
+
<Tooltip>
|
|
13077
|
+
<TooltipTrigger asChild>
|
|
13078
|
+
<span className="inline-flex cursor-default">
|
|
13079
|
+
<Info className="size-3.5 text-semantic-text-muted shrink-0" />
|
|
13080
|
+
</span>
|
|
13081
|
+
</TooltipTrigger>
|
|
13082
|
+
<TooltipContent>
|
|
13083
|
+
<p className="m-0">Upload documents and files to train your bot with your company knowledge.</p>
|
|
13084
|
+
<TooltipArrow />
|
|
13085
|
+
</TooltipContent>
|
|
13086
|
+
</Tooltip>
|
|
13071
13087
|
</div>
|
|
13072
13088
|
<button
|
|
13073
13089
|
type="button"
|
|
@@ -13079,7 +13095,7 @@ function KnowledgeBase({
|
|
|
13079
13095
|
</button>
|
|
13080
13096
|
</div>
|
|
13081
13097
|
{/* File list */}
|
|
13082
|
-
<div className="px-6">
|
|
13098
|
+
<div className="px-4 sm:px-6">
|
|
13083
13099
|
{files.length === 0 ? (
|
|
13084
13100
|
<p className="m-0 text-sm text-semantic-text-muted text-center py-5">
|
|
13085
13101
|
No files added yet. Click “+ Files” to upload.
|
|
@@ -13091,9 +13107,9 @@ function KnowledgeBase({
|
|
|
13091
13107
|
return (
|
|
13092
13108
|
<div
|
|
13093
13109
|
key={file.id}
|
|
13094
|
-
className="flex items-center justify-between py-4"
|
|
13110
|
+
className="flex flex-wrap items-center justify-between gap-2 py-4"
|
|
13095
13111
|
>
|
|
13096
|
-
<div className="flex items-center gap-2 min-w-0">
|
|
13112
|
+
<div className="flex items-center gap-2 min-w-0 flex-1">
|
|
13097
13113
|
<span className="text-sm text-semantic-text-primary truncate">
|
|
13098
13114
|
File {file.name}
|
|
13099
13115
|
</span>
|
|
@@ -13105,7 +13121,7 @@ function KnowledgeBase({
|
|
|
13105
13121
|
{status.label}
|
|
13106
13122
|
</Badge>
|
|
13107
13123
|
</div>
|
|
13108
|
-
<div className="flex items-center gap-1 shrink-0
|
|
13124
|
+
<div className="flex items-center gap-1 shrink-0">
|
|
13109
13125
|
<button
|
|
13110
13126
|
type="button"
|
|
13111
13127
|
onClick={() => onDownload?.(file.id)}
|
|
@@ -13151,12 +13167,22 @@ function FunctionsSection({
|
|
|
13151
13167
|
return (
|
|
13152
13168
|
<div className="bg-semantic-bg-primary border border-semantic-border-layout rounded-lg overflow-hidden">
|
|
13153
13169
|
{/* Header */}
|
|
13154
|
-
<div className="flex items-center justify-between px-6 py-4 border-b border-semantic-border-layout">
|
|
13170
|
+
<div className="flex items-center justify-between px-4 sm:px-6 py-4 border-b border-semantic-border-layout">
|
|
13155
13171
|
<div className="flex items-center gap-1.5">
|
|
13156
13172
|
<h2 className="m-0 text-base font-semibold text-semantic-text-primary">
|
|
13157
13173
|
Functions
|
|
13158
13174
|
</h2>
|
|
13159
|
-
<
|
|
13175
|
+
<Tooltip>
|
|
13176
|
+
<TooltipTrigger asChild>
|
|
13177
|
+
<span className="inline-flex cursor-default">
|
|
13178
|
+
<Info className="size-3.5 text-semantic-text-muted shrink-0" />
|
|
13179
|
+
</span>
|
|
13180
|
+
</TooltipTrigger>
|
|
13181
|
+
<TooltipContent>
|
|
13182
|
+
<p className="m-0">Add custom API functions the bot can call to fetch or submit data during conversations.</p>
|
|
13183
|
+
<TooltipArrow />
|
|
13184
|
+
</TooltipContent>
|
|
13185
|
+
</Tooltip>
|
|
13160
13186
|
</div>
|
|
13161
13187
|
<button
|
|
13162
13188
|
type="button"
|
|
@@ -13168,7 +13194,7 @@ function FunctionsSection({
|
|
|
13168
13194
|
</button>
|
|
13169
13195
|
</div>
|
|
13170
13196
|
{/* Function list */}
|
|
13171
|
-
<div className="px-6 py-4">
|
|
13197
|
+
<div className="px-4 sm:px-6 py-4">
|
|
13172
13198
|
{functions.length === 0 ? (
|
|
13173
13199
|
<p className="m-0 text-sm text-semantic-text-muted text-center py-2">
|
|
13174
13200
|
No functions added yet.
|
|
@@ -13178,16 +13204,16 @@ function FunctionsSection({
|
|
|
13178
13204
|
{functions.map((fn) => (
|
|
13179
13205
|
<div
|
|
13180
13206
|
key={fn.id}
|
|
13181
|
-
className="flex items-center
|
|
13207
|
+
className="flex flex-wrap items-center gap-2 px-4 py-3 rounded border border-semantic-border-layout bg-semantic-bg-primary"
|
|
13182
13208
|
>
|
|
13183
|
-
<div className="flex items-center gap-2 min-w-0">
|
|
13209
|
+
<div className="flex items-center gap-2 min-w-0 flex-1">
|
|
13184
13210
|
<Info className="size-4 text-semantic-text-muted shrink-0" />
|
|
13185
13211
|
<span className="text-sm text-semantic-text-primary truncate">
|
|
13186
13212
|
{fn.name}
|
|
13187
13213
|
</span>
|
|
13188
13214
|
</div>
|
|
13189
13215
|
{fn.isBuiltIn && (
|
|
13190
|
-
<Badge size="sm" className="font-normal shrink-0
|
|
13216
|
+
<Badge size="sm" className="font-normal shrink-0">
|
|
13191
13217
|
Built-in
|
|
13192
13218
|
</Badge>
|
|
13193
13219
|
)}
|
|
@@ -13212,15 +13238,25 @@ function FrustrationHandoverAccordion({
|
|
|
13212
13238
|
<div className="bg-semantic-bg-primary border border-semantic-border-layout rounded-lg overflow-hidden">
|
|
13213
13239
|
<Accordion type="single">
|
|
13214
13240
|
<AccordionItem value="frustration">
|
|
13215
|
-
<AccordionTrigger className="px-6 py-5 border-b border-semantic-border-layout hover:no-underline">
|
|
13241
|
+
<AccordionTrigger className="px-4 sm:px-6 py-5 border-b border-semantic-border-layout hover:no-underline">
|
|
13216
13242
|
<span className="flex items-center gap-1.5 text-base font-semibold text-semantic-text-primary">
|
|
13217
13243
|
Frustration Handover
|
|
13218
|
-
<
|
|
13244
|
+
<Tooltip>
|
|
13245
|
+
<TooltipTrigger asChild>
|
|
13246
|
+
<span className="inline-flex cursor-default">
|
|
13247
|
+
<Info className="size-3.5 text-semantic-text-muted shrink-0" />
|
|
13248
|
+
</span>
|
|
13249
|
+
</TooltipTrigger>
|
|
13250
|
+
<TooltipContent>
|
|
13251
|
+
<p className="m-0">Automatically transfer the call to a human agent when the bot detects customer frustration.</p>
|
|
13252
|
+
<TooltipArrow />
|
|
13253
|
+
</TooltipContent>
|
|
13254
|
+
</Tooltip>
|
|
13219
13255
|
</span>
|
|
13220
13256
|
</AccordionTrigger>
|
|
13221
13257
|
<AccordionContent>
|
|
13222
13258
|
<div className="flex flex-col gap-6 pt-0 pb-2">
|
|
13223
|
-
<div className="flex items-center justify-between px-6 py-2.5">
|
|
13259
|
+
<div className="flex items-center justify-between px-4 sm:px-6 py-2.5">
|
|
13224
13260
|
<span className="text-sm text-semantic-text-primary">
|
|
13225
13261
|
Enable frustration-based escalation
|
|
13226
13262
|
</span>
|
|
@@ -13231,19 +13267,22 @@ function FrustrationHandoverAccordion({
|
|
|
13231
13267
|
}
|
|
13232
13268
|
/>
|
|
13233
13269
|
</div>
|
|
13234
|
-
<div className="px-6 pb-2">
|
|
13270
|
+
<div className="px-4 sm:px-6 pb-2">
|
|
13235
13271
|
<Field label="Escalation Department">
|
|
13236
|
-
<
|
|
13237
|
-
|
|
13238
|
-
|
|
13239
|
-
onChange={(v) => onChange({ escalationDepartment: v })}
|
|
13272
|
+
<Select
|
|
13273
|
+
value={data.escalationDepartment || undefined}
|
|
13274
|
+
onValueChange={(v) => onChange({ escalationDepartment: v })}
|
|
13240
13275
|
disabled={!data.frustrationHandoverEnabled}
|
|
13241
|
-
|
|
13242
|
-
|
|
13243
|
-
|
|
13244
|
-
|
|
13245
|
-
|
|
13246
|
-
|
|
13276
|
+
>
|
|
13277
|
+
<SelectTrigger>
|
|
13278
|
+
<SelectValue placeholder="Select department/user" />
|
|
13279
|
+
</SelectTrigger>
|
|
13280
|
+
<SelectContent>
|
|
13281
|
+
<SelectItem value="support">Support</SelectItem>
|
|
13282
|
+
<SelectItem value="sales">Sales</SelectItem>
|
|
13283
|
+
<SelectItem value="billing">Billing</SelectItem>
|
|
13284
|
+
</SelectContent>
|
|
13285
|
+
</Select>
|
|
13247
13286
|
</Field>
|
|
13248
13287
|
</div>
|
|
13249
13288
|
</div>
|
|
@@ -13267,31 +13306,35 @@ function NumberSpinner({
|
|
|
13267
13306
|
max?: number;
|
|
13268
13307
|
}) {
|
|
13269
13308
|
return (
|
|
13270
|
-
<div className="flex
|
|
13309
|
+
<div className="flex items-center gap-2.5 w-full h-10 px-4 border border-semantic-border-layout bg-semantic-bg-primary rounded hover:border-semantic-border-input-focus focus-within:border-semantic-border-input-focus focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]">
|
|
13271
13310
|
<input
|
|
13272
13311
|
type="number"
|
|
13273
13312
|
value={value}
|
|
13274
13313
|
min={min}
|
|
13275
13314
|
max={max}
|
|
13276
13315
|
onChange={(e) => onChange(Number(e.target.value))}
|
|
13277
|
-
className="flex-1
|
|
13316
|
+
className="flex-1 text-sm text-semantic-text-primary bg-transparent outline-none [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
|
13278
13317
|
/>
|
|
13279
|
-
<div className="flex flex-col shrink-0
|
|
13318
|
+
<div className="flex flex-col items-center shrink-0 size-5 overflow-hidden">
|
|
13280
13319
|
<button
|
|
13281
13320
|
type="button"
|
|
13282
13321
|
onClick={() => onChange(Math.min(max, value + 1))}
|
|
13283
|
-
className="flex-1
|
|
13322
|
+
className="flex flex-1 items-center justify-center w-full text-semantic-text-muted hover:text-semantic-text-primary transition-colors"
|
|
13284
13323
|
aria-label="Increase"
|
|
13285
13324
|
>
|
|
13286
|
-
|
|
13325
|
+
<svg width="10" height="6" viewBox="0 0 10 6" fill="currentColor" aria-hidden="true">
|
|
13326
|
+
<path d="M5 0L10 6H0L5 0Z" />
|
|
13327
|
+
</svg>
|
|
13287
13328
|
</button>
|
|
13288
13329
|
<button
|
|
13289
13330
|
type="button"
|
|
13290
13331
|
onClick={() => onChange(Math.max(min, value - 1))}
|
|
13291
|
-
className="flex-1
|
|
13332
|
+
className="flex flex-1 items-center justify-center w-full text-semantic-text-muted hover:text-semantic-text-primary transition-colors"
|
|
13292
13333
|
aria-label="Decrease"
|
|
13293
13334
|
>
|
|
13294
|
-
|
|
13335
|
+
<svg width="10" height="6" viewBox="0 0 10 6" fill="currentColor" aria-hidden="true">
|
|
13336
|
+
<path d="M5 6L0 0H10L5 6Z" />
|
|
13337
|
+
</svg>
|
|
13295
13338
|
</button>
|
|
13296
13339
|
</div>
|
|
13297
13340
|
</div>
|
|
@@ -13309,7 +13352,7 @@ function AdvancedSettingsAccordion({
|
|
|
13309
13352
|
<div className="bg-semantic-bg-primary border border-semantic-border-layout rounded-lg overflow-hidden">
|
|
13310
13353
|
<Accordion type="single">
|
|
13311
13354
|
<AccordionItem value="advanced">
|
|
13312
|
-
<AccordionTrigger className="px-6 py-5 border-b border-semantic-border-layout hover:no-underline">
|
|
13355
|
+
<AccordionTrigger className="px-4 sm:px-6 py-5 border-b border-semantic-border-layout hover:no-underline">
|
|
13313
13356
|
<span className="text-base font-semibold text-semantic-text-primary">
|
|
13314
13357
|
Advanced Settings
|
|
13315
13358
|
</span>
|
|
@@ -13317,7 +13360,7 @@ function AdvancedSettingsAccordion({
|
|
|
13317
13360
|
<AccordionContent>
|
|
13318
13361
|
<div className="flex flex-col">
|
|
13319
13362
|
{/* Number fields section */}
|
|
13320
|
-
<div className="px-6 pt-5 pb-6 flex flex-col gap-5 border-b border-semantic-border-layout">
|
|
13363
|
+
<div className="px-4 sm:px-6 pt-5 pb-6 flex flex-col gap-5 border-b border-semantic-border-layout">
|
|
13321
13364
|
<Field label="Silence Timeout (seconds)">
|
|
13322
13365
|
<NumberSpinner
|
|
13323
13366
|
value={data.silenceTimeout ?? 15}
|
|
@@ -13344,7 +13387,7 @@ function AdvancedSettingsAccordion({
|
|
|
13344
13387
|
</div>
|
|
13345
13388
|
|
|
13346
13389
|
{/* Interruption Handling \u2014 separated by divider */}
|
|
13347
|
-
<div className="px-6 py-5 flex items-center gap-3">
|
|
13390
|
+
<div className="px-4 sm:px-6 py-5 flex items-center gap-3">
|
|
13348
13391
|
<div className="flex flex-col gap-0.5 flex-1 min-w-0">
|
|
13349
13392
|
<span className="text-sm font-semibold text-semantic-text-primary">
|
|
13350
13393
|
Interruption Handling
|
|
@@ -13427,9 +13470,10 @@ export const IvrBotConfig = React.forwardRef<HTMLDivElement, IvrBotConfigProps>(
|
|
|
13427
13470
|
};
|
|
13428
13471
|
|
|
13429
13472
|
return (
|
|
13473
|
+
<TooltipProvider delayDuration={300}>
|
|
13430
13474
|
<div ref={ref} className={cn("flex flex-col min-h-screen bg-semantic-bg-ui", className)}>
|
|
13431
13475
|
{/* Page header */}
|
|
13432
|
-
<header className="flex items-center justify-between px-6 h-[76px] bg-semantic-bg-primary border-b border-semantic-border-layout shrink-0">
|
|
13476
|
+
<header className="flex flex-wrap items-center justify-between gap-3 px-4 sm:px-6 min-h-[76px] py-3 bg-semantic-bg-primary border-b border-semantic-border-layout shrink-0">
|
|
13433
13477
|
<div className="flex items-center gap-3">
|
|
13434
13478
|
<button
|
|
13435
13479
|
type="button"
|
|
@@ -13446,9 +13490,9 @@ export const IvrBotConfig = React.forwardRef<HTMLDivElement, IvrBotConfigProps>(
|
|
|
13446
13490
|
{botType}
|
|
13447
13491
|
</Badge>
|
|
13448
13492
|
</div>
|
|
13449
|
-
<div className="flex items-center gap-3">
|
|
13493
|
+
<div className="flex flex-wrap items-center gap-2 sm:gap-3">
|
|
13450
13494
|
{lastUpdatedAt && (
|
|
13451
|
-
<span className="text-sm text-semantic-text-muted">
|
|
13495
|
+
<span className="hidden sm:inline text-sm text-semantic-text-muted">
|
|
13452
13496
|
Last updated at: {lastUpdatedAt}
|
|
13453
13497
|
</span>
|
|
13454
13498
|
)}
|
|
@@ -13469,17 +13513,17 @@ export const IvrBotConfig = React.forwardRef<HTMLDivElement, IvrBotConfigProps>(
|
|
|
13469
13513
|
</div>
|
|
13470
13514
|
</header>
|
|
13471
13515
|
|
|
13472
|
-
{/* Body \u2014 two-column
|
|
13473
|
-
<div className="flex flex-1 gap-6 px-6 py-6 max-w-[1220px] mx-auto w-full">
|
|
13516
|
+
{/* Body \u2014 single column on mobile, two-column on large screens */}
|
|
13517
|
+
<div className="flex flex-col lg:flex-row flex-1 gap-6 px-4 sm:px-6 py-6 max-w-[1220px] mx-auto w-full">
|
|
13474
13518
|
{/* Left column */}
|
|
13475
|
-
<div className="flex flex-col gap-6 flex-[3] min-w-0">
|
|
13519
|
+
<div className="flex flex-col gap-6 lg:flex-[3] min-w-0">
|
|
13476
13520
|
<WhoTheBotIs data={data} onChange={update} />
|
|
13477
13521
|
<HowItBehaves data={data} onChange={update} />
|
|
13478
13522
|
<FallbackPromptsAccordion data={data} onChange={update} />
|
|
13479
13523
|
</div>
|
|
13480
13524
|
|
|
13481
13525
|
{/* Right column */}
|
|
13482
|
-
<div className="flex flex-col gap-6 flex-[2] min-w-0">
|
|
13526
|
+
<div className="flex flex-col gap-6 lg:flex-[2] min-w-0">
|
|
13483
13527
|
<KnowledgeBase
|
|
13484
13528
|
files={data.knowledgeBaseFiles}
|
|
13485
13529
|
onSaveFiles={onSaveKnowledgeFiles}
|
|
@@ -13511,6 +13555,7 @@ export const IvrBotConfig = React.forwardRef<HTMLDivElement, IvrBotConfigProps>(
|
|
|
13511
13555
|
onTestApi={onTestApi}
|
|
13512
13556
|
/>
|
|
13513
13557
|
</div>
|
|
13558
|
+
</TooltipProvider>
|
|
13514
13559
|
);
|
|
13515
13560
|
}
|
|
13516
13561
|
);
|
|
@@ -13521,7 +13566,7 @@ IvrBotConfig.displayName = "IvrBotConfig";
|
|
|
13521
13566
|
{
|
|
13522
13567
|
name: "create-function-modal.tsx",
|
|
13523
13568
|
content: prefixTailwindClasses(`import * as React from "react";
|
|
13524
|
-
import { Trash2
|
|
13569
|
+
import { Trash2 } from "lucide-react";
|
|
13525
13570
|
import { cn } from "../../../lib/utils";
|
|
13526
13571
|
import {
|
|
13527
13572
|
Dialog,
|
|
@@ -13530,6 +13575,13 @@ import {
|
|
|
13530
13575
|
DialogTitle,
|
|
13531
13576
|
} from "../dialog";
|
|
13532
13577
|
import { Button } from "../button";
|
|
13578
|
+
import {
|
|
13579
|
+
Select,
|
|
13580
|
+
SelectTrigger,
|
|
13581
|
+
SelectValue,
|
|
13582
|
+
SelectContent,
|
|
13583
|
+
SelectItem,
|
|
13584
|
+
} from "../select";
|
|
13533
13585
|
import type {
|
|
13534
13586
|
CreateFunctionModalProps,
|
|
13535
13587
|
CreateFunctionData,
|
|
@@ -13571,64 +13623,68 @@ function KeyValueTable({
|
|
|
13571
13623
|
return (
|
|
13572
13624
|
<div className="flex flex-col gap-1.5">
|
|
13573
13625
|
<span className="text-xs text-semantic-text-muted">{label}</span>
|
|
13574
|
-
<div className="border border-semantic-border-layout
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
<div className="flex
|
|
13578
|
-
|
|
13626
|
+
<div className="w-full overflow-x-auto rounded border border-semantic-border-layout">
|
|
13627
|
+
<div className="min-w-[380px]">
|
|
13628
|
+
{/* Header row \u2014 always visible */}
|
|
13629
|
+
<div className="flex bg-semantic-bg-ui border-b border-semantic-border-layout">
|
|
13630
|
+
<div className="flex-1 px-3 py-2.5 text-sm font-semibold text-semantic-text-muted border-r border-semantic-border-layout">
|
|
13631
|
+
Key
|
|
13632
|
+
</div>
|
|
13633
|
+
<div className="flex-[2] px-3 py-2.5 text-sm font-semibold text-semantic-text-muted">
|
|
13634
|
+
Value
|
|
13635
|
+
</div>
|
|
13636
|
+
<div className="w-10" />
|
|
13579
13637
|
</div>
|
|
13580
|
-
|
|
13581
|
-
|
|
13638
|
+
{/* Data rows \u2014 scrollable vertically */}
|
|
13639
|
+
<div className="max-h-[160px] overflow-y-auto [&::-webkit-scrollbar]:hidden [scrollbar-width:none]">
|
|
13640
|
+
{rows.map((row) => (
|
|
13641
|
+
<div
|
|
13642
|
+
key={row.id}
|
|
13643
|
+
className="flex border-b border-semantic-border-layout last:border-b-0"
|
|
13644
|
+
>
|
|
13645
|
+
<input
|
|
13646
|
+
type="text"
|
|
13647
|
+
value={row.key}
|
|
13648
|
+
onChange={(e) => handleKeyChange(row.id, e.target.value)}
|
|
13649
|
+
placeholder="Key"
|
|
13650
|
+
className="flex-1 px-3 py-2.5 text-sm text-semantic-text-primary placeholder:text-semantic-text-placeholder bg-semantic-bg-primary border-r border-semantic-border-layout outline-none focus:bg-semantic-bg-hover"
|
|
13651
|
+
/>
|
|
13652
|
+
<input
|
|
13653
|
+
type="text"
|
|
13654
|
+
value={row.value}
|
|
13655
|
+
onChange={(e) => handleValueChange(row.id, e.target.value)}
|
|
13656
|
+
placeholder="Type {{ to add variables"
|
|
13657
|
+
className="flex-[2] px-3 py-2.5 text-sm text-semantic-text-primary placeholder:text-semantic-text-placeholder bg-semantic-bg-primary outline-none focus:bg-semantic-bg-hover"
|
|
13658
|
+
/>
|
|
13659
|
+
<button
|
|
13660
|
+
type="button"
|
|
13661
|
+
onClick={() => handleDelete(row.id)}
|
|
13662
|
+
className="w-10 flex items-center justify-center text-semantic-text-muted hover:text-semantic-error-primary hover:bg-semantic-error-surface transition-colors"
|
|
13663
|
+
aria-label="Delete row"
|
|
13664
|
+
>
|
|
13665
|
+
<Trash2 className="size-3.5" />
|
|
13666
|
+
</button>
|
|
13667
|
+
</div>
|
|
13668
|
+
))}
|
|
13582
13669
|
</div>
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
{/* Data rows */}
|
|
13586
|
-
{rows.map((row) => (
|
|
13587
|
-
<div
|
|
13588
|
-
key={row.id}
|
|
13589
|
-
className="flex border-b border-semantic-border-layout last:border-b-0"
|
|
13590
|
-
>
|
|
13670
|
+
{/* Empty input row \u2014 always visible at bottom */}
|
|
13671
|
+
<div className="flex border-t border-semantic-border-layout">
|
|
13591
13672
|
<input
|
|
13592
13673
|
type="text"
|
|
13593
|
-
value={row.key}
|
|
13594
|
-
onChange={(e) => handleKeyChange(row.id, e.target.value)}
|
|
13595
13674
|
placeholder="Key"
|
|
13596
|
-
|
|
13675
|
+
readOnly
|
|
13676
|
+
onClick={handleAdd}
|
|
13677
|
+
className="flex-1 px-3 py-2.5 text-sm placeholder:text-semantic-text-placeholder bg-semantic-bg-primary border-r border-semantic-border-layout outline-none cursor-pointer"
|
|
13597
13678
|
/>
|
|
13598
13679
|
<input
|
|
13599
13680
|
type="text"
|
|
13600
|
-
value={row.value}
|
|
13601
|
-
onChange={(e) => handleValueChange(row.id, e.target.value)}
|
|
13602
13681
|
placeholder="Type {{ to add variables"
|
|
13603
|
-
|
|
13682
|
+
readOnly
|
|
13683
|
+
onClick={handleAdd}
|
|
13684
|
+
className="flex-[2] px-3 py-2.5 text-sm placeholder:text-semantic-text-placeholder bg-semantic-bg-primary outline-none cursor-pointer"
|
|
13604
13685
|
/>
|
|
13605
|
-
<
|
|
13606
|
-
type="button"
|
|
13607
|
-
onClick={() => handleDelete(row.id)}
|
|
13608
|
-
className="w-10 flex items-center justify-center text-semantic-text-muted hover:text-semantic-error-primary hover:bg-semantic-error-surface transition-colors"
|
|
13609
|
-
aria-label="Delete row"
|
|
13610
|
-
>
|
|
13611
|
-
<Trash2 className="size-3.5" />
|
|
13612
|
-
</button>
|
|
13686
|
+
<div className="w-10" />
|
|
13613
13687
|
</div>
|
|
13614
|
-
))}
|
|
13615
|
-
{/* Empty input row */}
|
|
13616
|
-
<div className="flex">
|
|
13617
|
-
<input
|
|
13618
|
-
type="text"
|
|
13619
|
-
placeholder="Key"
|
|
13620
|
-
readOnly
|
|
13621
|
-
onClick={handleAdd}
|
|
13622
|
-
className="flex-1 px-3 py-2.5 text-sm placeholder:text-semantic-text-muted bg-semantic-bg-primary border-r border-semantic-border-layout outline-none cursor-pointer"
|
|
13623
|
-
/>
|
|
13624
|
-
<input
|
|
13625
|
-
type="text"
|
|
13626
|
-
placeholder="Type {{ to add variables"
|
|
13627
|
-
readOnly
|
|
13628
|
-
onClick={handleAdd}
|
|
13629
|
-
className="flex-[2] px-3 py-2.5 text-sm placeholder:text-semantic-text-muted bg-semantic-bg-primary outline-none cursor-pointer"
|
|
13630
|
-
/>
|
|
13631
|
-
<div className="w-10" />
|
|
13632
13688
|
</div>
|
|
13633
13689
|
</div>
|
|
13634
13690
|
</div>
|
|
@@ -13730,7 +13786,15 @@ export const CreateFunctionModal = React.forwardRef<
|
|
|
13730
13786
|
Functions Name{" "}
|
|
13731
13787
|
<span className="text-semantic-error-primary font-semibold">*</span>
|
|
13732
13788
|
</label>
|
|
13733
|
-
<div
|
|
13789
|
+
<div
|
|
13790
|
+
className={cn(
|
|
13791
|
+
"flex items-center h-10 rounded border",
|
|
13792
|
+
"border-semantic-border-input bg-semantic-bg-primary",
|
|
13793
|
+
"hover:border-semantic-border-input-focus",
|
|
13794
|
+
"focus-within:border-semantic-border-input-focus focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
|
|
13795
|
+
"transition-shadow"
|
|
13796
|
+
)}
|
|
13797
|
+
>
|
|
13734
13798
|
<input
|
|
13735
13799
|
id="fn-name"
|
|
13736
13800
|
type="text"
|
|
@@ -13738,15 +13802,9 @@ export const CreateFunctionModal = React.forwardRef<
|
|
|
13738
13802
|
maxLength={FUNCTION_NAME_MAX}
|
|
13739
13803
|
onChange={(e) => setName(e.target.value)}
|
|
13740
13804
|
placeholder="Enter Name of the function"
|
|
13741
|
-
className=
|
|
13742
|
-
"w-full h-10 px-4 py-2.5 pr-16 text-sm rounded border",
|
|
13743
|
-
"border-semantic-border-input bg-semantic-bg-primary",
|
|
13744
|
-
"text-semantic-text-primary placeholder:text-semantic-text-muted",
|
|
13745
|
-
"outline-none hover:border-semantic-border-input-focus",
|
|
13746
|
-
"focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]"
|
|
13747
|
-
)}
|
|
13805
|
+
className="flex-1 h-full px-4 text-sm bg-transparent text-semantic-text-primary placeholder:text-semantic-text-placeholder outline-none"
|
|
13748
13806
|
/>
|
|
13749
|
-
<span className="
|
|
13807
|
+
<span className="px-3 shrink-0 text-xs italic text-semantic-text-muted">
|
|
13750
13808
|
{name.length}/{FUNCTION_NAME_MAX}
|
|
13751
13809
|
</span>
|
|
13752
13810
|
</div>
|
|
@@ -13770,7 +13828,7 @@ export const CreateFunctionModal = React.forwardRef<
|
|
|
13770
13828
|
className={cn(
|
|
13771
13829
|
"w-full px-4 py-2.5 text-sm rounded border",
|
|
13772
13830
|
"border-semantic-border-input bg-semantic-bg-primary resize-none",
|
|
13773
|
-
"text-semantic-text-primary placeholder:text-semantic-text-
|
|
13831
|
+
"text-semantic-text-primary placeholder:text-semantic-text-placeholder",
|
|
13774
13832
|
"outline-none hover:border-semantic-border-input-focus",
|
|
13775
13833
|
"focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]"
|
|
13776
13834
|
)}
|
|
@@ -13782,6 +13840,7 @@ export const CreateFunctionModal = React.forwardRef<
|
|
|
13782
13840
|
variant="default"
|
|
13783
13841
|
onClick={handleNext}
|
|
13784
13842
|
disabled={!isStep1Valid}
|
|
13843
|
+
className="w-full sm:w-auto"
|
|
13785
13844
|
>
|
|
13786
13845
|
Next
|
|
13787
13846
|
</Button>
|
|
@@ -13791,150 +13850,149 @@ export const CreateFunctionModal = React.forwardRef<
|
|
|
13791
13850
|
|
|
13792
13851
|
{step === 2 && (
|
|
13793
13852
|
<div className="flex flex-col gap-6">
|
|
13794
|
-
{/*
|
|
13795
|
-
<div className="
|
|
13796
|
-
<
|
|
13797
|
-
|
|
13798
|
-
|
|
13799
|
-
|
|
13800
|
-
<
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
13804
|
-
|
|
13805
|
-
|
|
13806
|
-
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13815
|
-
|
|
13853
|
+
{/* Horizontally scrollable form area */}
|
|
13854
|
+
<div className="overflow-x-auto [&::-webkit-scrollbar]:hidden [scrollbar-width:none]">
|
|
13855
|
+
<div className="flex flex-col gap-6 min-w-[440px]">
|
|
13856
|
+
{/* API URL */}
|
|
13857
|
+
<div className="flex flex-col gap-1">
|
|
13858
|
+
<span className="text-xs text-semantic-text-muted tracking-[0.048px]">API url</span>
|
|
13859
|
+
<div className="flex flex-row border border-semantic-border-input rounded overflow-hidden hover:border-semantic-border-input-focus focus-within:border-semantic-border-input-focus focus-within:shadow-[0_0_0_1px_rgba(43,188,202,0.15)] transition-shadow">
|
|
13860
|
+
{/* Method selector */}
|
|
13861
|
+
<Select value={method} onValueChange={(v) => setMethod(v as HttpMethod)}>
|
|
13862
|
+
<SelectTrigger
|
|
13863
|
+
className="w-[104px] shrink-0 rounded-none border-0 border-r border-semantic-border-input focus:shadow-none"
|
|
13864
|
+
aria-label="HTTP method"
|
|
13865
|
+
>
|
|
13866
|
+
<SelectValue />
|
|
13867
|
+
</SelectTrigger>
|
|
13868
|
+
<SelectContent>
|
|
13869
|
+
{HTTP_METHODS.map((m) => (
|
|
13870
|
+
<SelectItem key={m} value={m}>{m}</SelectItem>
|
|
13871
|
+
))}
|
|
13872
|
+
</SelectContent>
|
|
13873
|
+
</Select>
|
|
13874
|
+
{/* URL input */}
|
|
13875
|
+
<input
|
|
13876
|
+
type="text"
|
|
13877
|
+
value={url}
|
|
13878
|
+
onChange={(e) => setUrl(e.target.value)}
|
|
13879
|
+
placeholder="Enter URL or Type {{ to add variables"
|
|
13880
|
+
className="flex-1 min-w-0 h-10 px-3 text-sm text-semantic-text-primary placeholder:text-semantic-text-placeholder bg-semantic-bg-primary border-0 outline-none"
|
|
13881
|
+
/>
|
|
13882
|
+
</div>
|
|
13816
13883
|
</div>
|
|
13817
|
-
<input
|
|
13818
|
-
type="text"
|
|
13819
|
-
value={url}
|
|
13820
|
-
onChange={(e) => setUrl(e.target.value)}
|
|
13821
|
-
placeholder="Enter URL or Type {{ to add variables"
|
|
13822
|
-
className="flex-1 px-4 text-sm text-semantic-text-primary placeholder:text-semantic-text-muted bg-semantic-bg-primary outline-none"
|
|
13823
|
-
/>
|
|
13824
|
-
</div>
|
|
13825
|
-
</div>
|
|
13826
13884
|
|
|
13827
|
-
|
|
13828
|
-
|
|
13829
|
-
|
|
13830
|
-
|
|
13831
|
-
|
|
13832
|
-
|
|
13833
|
-
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
13837
|
-
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
|
|
13885
|
+
{/* Tabs */}
|
|
13886
|
+
<div className="flex flex-col gap-4">
|
|
13887
|
+
{/* Tabs row */}
|
|
13888
|
+
<div className="relative flex gap-8 border-b border-semantic-border-layout">
|
|
13889
|
+
{(["header", "queryParams", "body"] as FunctionTabType[]).map(
|
|
13890
|
+
(tab) => {
|
|
13891
|
+
const labels: Record<FunctionTabType, string> = {
|
|
13892
|
+
header: \`Header(\${tabCount.header})\`,
|
|
13893
|
+
queryParams: \`Query parameter(\${tabCount.queryParams})\`,
|
|
13894
|
+
body: "Body",
|
|
13895
|
+
};
|
|
13896
|
+
return (
|
|
13897
|
+
<button
|
|
13898
|
+
key={tab}
|
|
13899
|
+
type="button"
|
|
13900
|
+
onClick={() => setActiveTab(tab)}
|
|
13901
|
+
className={cn(
|
|
13902
|
+
"relative -mb-px px-2.5 py-1 pb-2 text-sm font-semibold transition-colors whitespace-nowrap",
|
|
13903
|
+
activeTab === tab
|
|
13904
|
+
? "text-semantic-text-secondary border-b-[1.5px] border-semantic-text-secondary"
|
|
13905
|
+
: "text-semantic-text-muted"
|
|
13906
|
+
)}
|
|
13907
|
+
>
|
|
13908
|
+
{labels[tab]}
|
|
13909
|
+
</button>
|
|
13910
|
+
);
|
|
13911
|
+
}
|
|
13912
|
+
)}
|
|
13913
|
+
</div>
|
|
13855
13914
|
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
/>
|
|
13870
|
-
)}
|
|
13871
|
-
{activeTab === "body" && (
|
|
13872
|
-
<div className="flex flex-col gap-1">
|
|
13873
|
-
<span className="text-xs text-semantic-text-muted">Body</span>
|
|
13874
|
-
<div className="relative">
|
|
13875
|
-
<textarea
|
|
13876
|
-
value={body}
|
|
13877
|
-
maxLength={BODY_MAX}
|
|
13878
|
-
onChange={(e) => setBody(e.target.value)}
|
|
13879
|
-
placeholder="Enter request body (JSON, XML etc). Type {{ to add variables"
|
|
13880
|
-
rows={6}
|
|
13881
|
-
className={cn(
|
|
13882
|
-
"w-full px-4 py-2.5 pb-7 text-sm rounded border resize-none",
|
|
13883
|
-
"border-semantic-border-input bg-semantic-bg-primary",
|
|
13884
|
-
"text-semantic-text-primary placeholder:text-semantic-text-muted",
|
|
13885
|
-
"outline-none hover:border-semantic-border-input-focus",
|
|
13886
|
-
"focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]"
|
|
13887
|
-
)}
|
|
13915
|
+
{/* Tab Content */}
|
|
13916
|
+
{activeTab === "header" && (
|
|
13917
|
+
<KeyValueTable
|
|
13918
|
+
rows={headers}
|
|
13919
|
+
onChange={setHeaders}
|
|
13920
|
+
label="Header"
|
|
13921
|
+
/>
|
|
13922
|
+
)}
|
|
13923
|
+
{activeTab === "queryParams" && (
|
|
13924
|
+
<KeyValueTable
|
|
13925
|
+
rows={queryParams}
|
|
13926
|
+
onChange={setQueryParams}
|
|
13927
|
+
label="Query parameter"
|
|
13888
13928
|
/>
|
|
13889
|
-
|
|
13890
|
-
|
|
13929
|
+
)}
|
|
13930
|
+
{activeTab === "body" && (
|
|
13931
|
+
<div className="flex flex-col gap-1">
|
|
13932
|
+
<span className="text-xs text-semantic-text-muted">Body</span>
|
|
13933
|
+
<div className="relative">
|
|
13934
|
+
<textarea
|
|
13935
|
+
value={body}
|
|
13936
|
+
maxLength={BODY_MAX}
|
|
13937
|
+
onChange={(e) => setBody(e.target.value)}
|
|
13938
|
+
placeholder="Enter request body (JSON, XML etc). Type {{ to add variables"
|
|
13939
|
+
rows={6}
|
|
13940
|
+
className={cn(
|
|
13941
|
+
"w-full px-4 py-2.5 pb-7 text-sm rounded border resize-none",
|
|
13942
|
+
"border-semantic-border-input bg-semantic-bg-primary",
|
|
13943
|
+
"text-semantic-text-primary placeholder:text-semantic-text-placeholder",
|
|
13944
|
+
"outline-none hover:border-semantic-border-input-focus",
|
|
13945
|
+
"focus:border-semantic-border-input-focus focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]"
|
|
13946
|
+
)}
|
|
13947
|
+
/>
|
|
13948
|
+
<span className="absolute bottom-2 right-3 text-xs italic text-semantic-text-muted">
|
|
13949
|
+
{body.length}/{BODY_MAX}
|
|
13950
|
+
</span>
|
|
13951
|
+
</div>
|
|
13952
|
+
</div>
|
|
13953
|
+
)}
|
|
13954
|
+
</div>
|
|
13955
|
+
|
|
13956
|
+
{/* Test Your API */}
|
|
13957
|
+
<div className="flex flex-col gap-4">
|
|
13958
|
+
<div className="flex flex-col gap-1.5">
|
|
13959
|
+
<span className="text-xs text-semantic-text-muted tracking-[0.048px]">
|
|
13960
|
+
Test Your API
|
|
13961
|
+
</span>
|
|
13962
|
+
<div className="border-t border-semantic-border-layout w-full" />
|
|
13963
|
+
</div>
|
|
13964
|
+
<div className="flex justify-end">
|
|
13965
|
+
<button
|
|
13966
|
+
type="button"
|
|
13967
|
+
onClick={handleTestApi}
|
|
13968
|
+
disabled={isTesting || !url.trim()}
|
|
13969
|
+
className="h-10 px-6 rounded text-sm font-semibold text-semantic-text-secondary bg-semantic-primary-surface disabled:opacity-50 disabled:cursor-not-allowed transition-colors hover:bg-semantic-primary-surface/80"
|
|
13970
|
+
>
|
|
13971
|
+
{isTesting ? "Testing..." : "Test API"}
|
|
13972
|
+
</button>
|
|
13973
|
+
</div>
|
|
13974
|
+
<div className="flex flex-col gap-1">
|
|
13975
|
+
<span className="text-xs text-semantic-text-muted">
|
|
13976
|
+
Response from API
|
|
13891
13977
|
</span>
|
|
13978
|
+
<textarea
|
|
13979
|
+
readOnly
|
|
13980
|
+
value={apiResponse}
|
|
13981
|
+
rows={4}
|
|
13982
|
+
className="w-full px-3 py-2.5 text-sm rounded border border-semantic-border-layout bg-semantic-bg-primary text-semantic-text-primary resize-none outline-none"
|
|
13983
|
+
placeholder=""
|
|
13984
|
+
/>
|
|
13892
13985
|
</div>
|
|
13893
13986
|
</div>
|
|
13894
|
-
)}
|
|
13895
|
-
</div>
|
|
13896
|
-
|
|
13897
|
-
{/* Test Your API */}
|
|
13898
|
-
<div className="flex flex-col gap-6">
|
|
13899
|
-
{/* Label stacked above full-width divider */}
|
|
13900
|
-
<div className="flex flex-col gap-1.5">
|
|
13901
|
-
<span className="text-xs text-semantic-text-muted tracking-[0.048px]">
|
|
13902
|
-
Test Your API
|
|
13903
|
-
</span>
|
|
13904
|
-
<div className="border-t border-semantic-border-layout w-full" />
|
|
13905
|
-
</div>
|
|
13906
|
-
{/* Test API button right-aligned */}
|
|
13907
|
-
<div className="flex justify-end">
|
|
13908
|
-
<button
|
|
13909
|
-
type="button"
|
|
13910
|
-
onClick={handleTestApi}
|
|
13911
|
-
disabled={isTesting || !url.trim()}
|
|
13912
|
-
className="h-10 px-6 rounded text-sm font-semibold text-semantic-text-secondary bg-semantic-primary-surface disabled:opacity-50 disabled:cursor-not-allowed transition-colors hover:bg-semantic-primary-surface/80"
|
|
13913
|
-
>
|
|
13914
|
-
{isTesting ? "Testing..." : "Test API"}
|
|
13915
|
-
</button>
|
|
13916
|
-
</div>
|
|
13917
|
-
{/* Row 3: Response from API */}
|
|
13918
|
-
<div className="flex flex-col gap-1">
|
|
13919
|
-
<span className="text-xs text-semantic-text-muted">
|
|
13920
|
-
Response from API
|
|
13921
|
-
</span>
|
|
13922
|
-
<textarea
|
|
13923
|
-
readOnly
|
|
13924
|
-
value={apiResponse}
|
|
13925
|
-
rows={4}
|
|
13926
|
-
className="w-full px-3 py-2.5 text-sm rounded border border-semantic-border-layout bg-semantic-bg-ui text-semantic-text-primary resize-none outline-none"
|
|
13927
|
-
placeholder=""
|
|
13928
|
-
/>
|
|
13929
13987
|
</div>
|
|
13930
13988
|
</div>
|
|
13931
13989
|
|
|
13932
|
-
{/* Footer */}
|
|
13933
|
-
<div className="flex justify-
|
|
13934
|
-
<Button variant="outline" onClick={handleBack}>
|
|
13990
|
+
{/* Footer \u2014 always full-width, outside the scroll area */}
|
|
13991
|
+
<div className="flex flex-row justify-between gap-3">
|
|
13992
|
+
<Button variant="outline" onClick={handleBack} className="flex-1 sm:flex-none sm:w-auto">
|
|
13935
13993
|
Back
|
|
13936
13994
|
</Button>
|
|
13937
|
-
<Button variant="default" onClick={handleSubmit}>
|
|
13995
|
+
<Button variant="default" onClick={handleSubmit} className="flex-1 sm:flex-none sm:w-auto">
|
|
13938
13996
|
Submit
|
|
13939
13997
|
</Button>
|
|
13940
13998
|
</div>
|