@budibase/frontend-core 3.27.4 → 3.27.5
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/package.json +2 -2
- package/src/api/user.ts +7 -3
- package/src/components/Chatbox/index.svelte +92 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/frontend-core",
|
|
3
|
-
"version": "3.27.
|
|
3
|
+
"version": "3.27.5",
|
|
4
4
|
"description": "Budibase frontend core libraries used in builder and client",
|
|
5
5
|
"author": "Budibase",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -24,5 +24,5 @@
|
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"vitest": "^3.2.4"
|
|
26
26
|
},
|
|
27
|
-
"gitHead": "
|
|
27
|
+
"gitHead": "46316dfbbf8e41a547bc8a4977ccd819a7515b9a"
|
|
28
28
|
}
|
package/src/api/user.ts
CHANGED
|
@@ -43,7 +43,10 @@ export interface UserEndpoints {
|
|
|
43
43
|
deleteUser: (userId: string) => Promise<DeleteUserResponse>
|
|
44
44
|
deleteUsers: (users: UserIdentifier[]) => Promise<BulkUserDeleted | undefined>
|
|
45
45
|
onboardUsers: (data: InviteUsersRequest) => Promise<InviteUsersResponse>
|
|
46
|
-
getUserInvite: (
|
|
46
|
+
getUserInvite: (
|
|
47
|
+
code: string,
|
|
48
|
+
tenantId?: string
|
|
49
|
+
) => Promise<CheckInviteResponse>
|
|
47
50
|
getUserInvites: () => Promise<GetUserInvitesResponse>
|
|
48
51
|
inviteUsers: (users: InviteUsersRequest) => Promise<InviteUsersResponse>
|
|
49
52
|
removeUserInvites: (
|
|
@@ -223,9 +226,10 @@ export const buildUserEndpoints = (API: BaseAPIClient): UserEndpoints => ({
|
|
|
223
226
|
* Retrieves the invitation associated with a provided code.
|
|
224
227
|
* @param code The unique code for the target invite
|
|
225
228
|
*/
|
|
226
|
-
getUserInvite: async code => {
|
|
229
|
+
getUserInvite: async (code, tenantId) => {
|
|
230
|
+
const query = tenantId ? `?tenantId=${encodeURIComponent(tenantId)}` : ""
|
|
227
231
|
return await API.get({
|
|
228
|
-
url: `/api/global/users/invite/${code}`,
|
|
232
|
+
url: `/api/global/users/invite/${code}${query}`,
|
|
229
233
|
})
|
|
230
234
|
},
|
|
231
235
|
|
|
@@ -31,10 +31,13 @@
|
|
|
31
31
|
chat: ChatConversationLike
|
|
32
32
|
persistConversation?: boolean
|
|
33
33
|
conversationStarters?: { prompt: string }[]
|
|
34
|
+
initialPrompt?: string
|
|
34
35
|
onchatsaved?: (_event: {
|
|
35
36
|
detail: { chatId?: string; chat: ChatConversationLike }
|
|
36
37
|
}) => void
|
|
37
38
|
isAgentPreviewChat?: boolean
|
|
39
|
+
readOnly?: boolean
|
|
40
|
+
readOnlyReason?: "disabled" | "deleted" | "offline"
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
let {
|
|
@@ -42,8 +45,11 @@
|
|
|
42
45
|
chat = $bindable(),
|
|
43
46
|
persistConversation = true,
|
|
44
47
|
conversationStarters = [],
|
|
48
|
+
initialPrompt = "",
|
|
45
49
|
onchatsaved,
|
|
46
50
|
isAgentPreviewChat = false,
|
|
51
|
+
readOnly = false,
|
|
52
|
+
readOnlyReason,
|
|
47
53
|
}: Props = $props()
|
|
48
54
|
|
|
49
55
|
let API = $state(
|
|
@@ -60,6 +66,7 @@
|
|
|
60
66
|
let textareaElement = $state<HTMLTextAreaElement>()
|
|
61
67
|
let expandedTools = $state<Record<string, boolean>>({})
|
|
62
68
|
let inputValue = $state("")
|
|
69
|
+
let lastInitialPrompt = $state("")
|
|
63
70
|
let reasoningTimers = $state<Record<string, number>>({})
|
|
64
71
|
|
|
65
72
|
const getReasoningText = (message: UIMessage<AgentMessageMetadata>) =>
|
|
@@ -141,6 +148,20 @@
|
|
|
141
148
|
tick().then(() => textareaElement?.focus())
|
|
142
149
|
}
|
|
143
150
|
|
|
151
|
+
$effect(() => {
|
|
152
|
+
if (!initialPrompt) {
|
|
153
|
+
lastInitialPrompt = ""
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (initialPrompt === lastInitialPrompt) {
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
lastInitialPrompt = initialPrompt
|
|
162
|
+
applyConversationStarter(initialPrompt)
|
|
163
|
+
})
|
|
164
|
+
|
|
144
165
|
const chatInstance = new Chat<UIMessage<AgentMessageMetadata>>({
|
|
145
166
|
transport: new DefaultChatTransport({
|
|
146
167
|
headers: () => ({ [Header.APP_ID]: workspaceId }),
|
|
@@ -198,12 +219,20 @@
|
|
|
198
219
|
let isBusy = $derived(
|
|
199
220
|
chatInstance.status === "streaming" || chatInstance.status === "submitted"
|
|
200
221
|
)
|
|
201
|
-
let hasMessages = $derived(Boolean(
|
|
222
|
+
let hasMessages = $derived(Boolean(messages?.length))
|
|
202
223
|
let showConversationStarters = $derived(
|
|
203
224
|
!isBusy &&
|
|
204
225
|
!hasMessages &&
|
|
205
226
|
conversationStarters.length > 0 &&
|
|
206
|
-
!isAgentPreviewChat
|
|
227
|
+
!isAgentPreviewChat &&
|
|
228
|
+
!readOnly
|
|
229
|
+
)
|
|
230
|
+
let readOnlyMessage = $derived(
|
|
231
|
+
readOnlyReason === "deleted"
|
|
232
|
+
? "This agent was deleted. Select another agent to resume chatting."
|
|
233
|
+
: readOnlyReason === "offline"
|
|
234
|
+
? "This agent is no longer live. Make it live in Settings to resume chatting."
|
|
235
|
+
: "This agent is disabled. Enable it in Settings to resume chatting."
|
|
207
236
|
)
|
|
208
237
|
|
|
209
238
|
let lastChatId = $state<string | undefined>(chat?._id)
|
|
@@ -262,6 +291,10 @@
|
|
|
262
291
|
}
|
|
263
292
|
|
|
264
293
|
const handleKeyDown = async (event: KeyboardEvent) => {
|
|
294
|
+
if (readOnly) {
|
|
295
|
+
return
|
|
296
|
+
}
|
|
297
|
+
|
|
265
298
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
266
299
|
event.preventDefault()
|
|
267
300
|
await sendMessage()
|
|
@@ -269,6 +302,10 @@
|
|
|
269
302
|
}
|
|
270
303
|
|
|
271
304
|
const sendMessage = async () => {
|
|
305
|
+
if (readOnly) {
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
|
|
272
309
|
const chatAppIdFromEnsure = await ensureChatApp()
|
|
273
310
|
|
|
274
311
|
if (!chat) {
|
|
@@ -351,7 +388,9 @@
|
|
|
351
388
|
mounted = true
|
|
352
389
|
ensureChatApp()
|
|
353
390
|
tick().then(() => {
|
|
354
|
-
|
|
391
|
+
if (!readOnly) {
|
|
392
|
+
textareaElement?.focus()
|
|
393
|
+
}
|
|
355
394
|
})
|
|
356
395
|
}
|
|
357
396
|
})
|
|
@@ -389,7 +428,7 @@
|
|
|
389
428
|
{/each}
|
|
390
429
|
</div>
|
|
391
430
|
</div>
|
|
392
|
-
{:else}
|
|
431
|
+
{:else if !hasMessages}
|
|
393
432
|
<div class="empty-state">
|
|
394
433
|
<div class="empty-state-icon">
|
|
395
434
|
<Icon
|
|
@@ -570,16 +609,26 @@
|
|
|
570
609
|
{/each}
|
|
571
610
|
</div>
|
|
572
611
|
|
|
573
|
-
|
|
574
|
-
<
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
612
|
+
{#if readOnly}
|
|
613
|
+
<div class="input-wrapper">
|
|
614
|
+
<div class="read-only-notice">
|
|
615
|
+
<Body size="S" color="var(--spectrum-global-color-gray-700)">
|
|
616
|
+
{readOnlyMessage}
|
|
617
|
+
</Body>
|
|
618
|
+
</div>
|
|
619
|
+
</div>
|
|
620
|
+
{:else}
|
|
621
|
+
<div class="input-wrapper">
|
|
622
|
+
<textarea
|
|
623
|
+
bind:value={inputValue}
|
|
624
|
+
bind:this={textareaElement}
|
|
625
|
+
class="input spectrum-Textfield-input"
|
|
626
|
+
onkeydown={handleKeyDown}
|
|
627
|
+
placeholder="Ask anything"
|
|
628
|
+
disabled={isBusy}
|
|
629
|
+
></textarea>
|
|
630
|
+
</div>
|
|
631
|
+
{/if}
|
|
583
632
|
</div>
|
|
584
633
|
|
|
585
634
|
<style>
|
|
@@ -616,36 +665,45 @@
|
|
|
616
665
|
.starter-section {
|
|
617
666
|
display: flex;
|
|
618
667
|
flex-direction: column;
|
|
619
|
-
|
|
668
|
+
align-items: center;
|
|
669
|
+
gap: var(--spacing-xl);
|
|
670
|
+
margin: auto 0;
|
|
620
671
|
}
|
|
621
672
|
|
|
622
673
|
.starter-title {
|
|
623
|
-
font-size:
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
674
|
+
font-size: 14px;
|
|
675
|
+
letter-spacing: 0;
|
|
676
|
+
color: var(--spectrum-global-color-gray-700);
|
|
677
|
+
text-align: center;
|
|
627
678
|
}
|
|
628
679
|
|
|
629
680
|
.starter-grid {
|
|
630
681
|
display: grid;
|
|
631
682
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
632
|
-
gap: var(--spacing-
|
|
683
|
+
gap: var(--spacing-m);
|
|
684
|
+
width: min(520px, 100%);
|
|
685
|
+
margin: 0 auto;
|
|
633
686
|
}
|
|
634
687
|
|
|
635
688
|
.starter-card {
|
|
636
|
-
border: 1px solid var(--
|
|
689
|
+
border: 1px solid var(--spectrum-global-color-gray-200);
|
|
637
690
|
border-radius: 12px;
|
|
638
691
|
padding: var(--spacing-m);
|
|
639
|
-
background: var(--
|
|
640
|
-
color: var(--spectrum-global-color-gray-
|
|
692
|
+
background: var(--spectrum-global-color-gray-50);
|
|
693
|
+
color: var(--spectrum-global-color-gray-800);
|
|
641
694
|
font: inherit;
|
|
642
|
-
|
|
695
|
+
font-size: 14px;
|
|
696
|
+
line-height: 1.4;
|
|
697
|
+
text-align: center;
|
|
643
698
|
cursor: pointer;
|
|
699
|
+
display: flex;
|
|
700
|
+
align-items: center;
|
|
701
|
+
justify-content: center;
|
|
644
702
|
}
|
|
645
703
|
|
|
646
704
|
.starter-card:hover {
|
|
647
|
-
border-color: var(--
|
|
648
|
-
background: var(--
|
|
705
|
+
border-color: var(--spectrum-global-color-gray-300);
|
|
706
|
+
background: var(--spectrum-global-color-gray-100);
|
|
649
707
|
}
|
|
650
708
|
|
|
651
709
|
.message {
|
|
@@ -688,6 +746,14 @@
|
|
|
688
746
|
line-height: 1.4;
|
|
689
747
|
}
|
|
690
748
|
|
|
749
|
+
.read-only-notice {
|
|
750
|
+
border: 1px solid var(--spectrum-global-color-gray-200);
|
|
751
|
+
border-radius: 10px;
|
|
752
|
+
padding: var(--spacing-m);
|
|
753
|
+
background-color: var(--spectrum-global-color-gray-50);
|
|
754
|
+
text-align: center;
|
|
755
|
+
}
|
|
756
|
+
|
|
691
757
|
.input {
|
|
692
758
|
width: 100%;
|
|
693
759
|
height: 100px;
|