@budibase/frontend-core 3.34.1 → 3.34.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@budibase/frontend-core",
3
- "version": "3.34.1",
3
+ "version": "3.34.2",
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": "a55111838ecb57332a3e62f3d9f08c6084936d66"
27
+ "gitHead": "4d4c308333cb78bd5454f322f983dc0da62e5505"
28
28
  }
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { createEventDispatcher, onMount } from "svelte"
3
- import { Body, Button, Icon, ProgressCircle } from "@budibase/bbui"
3
+ import { Body, Icon } from "@budibase/bbui"
4
4
  import type { ChatConversation, DraftChatConversation } from "@budibase/types"
5
5
  import Chatbox from "./index.svelte"
6
6
 
@@ -21,7 +21,6 @@
21
21
  }
22
22
 
23
23
  export let selectedAgentId: string | null = null
24
- export let selectedAgentName: string = ""
25
24
  export let enabledAgentList: EnabledAgentListItem[] = []
26
25
  export let conversationStarters: { prompt: string }[] = []
27
26
  export let agentAvailability: AgentAvailability = "ready"
@@ -29,14 +28,12 @@
29
28
  export let chat: ChatConversationLike
30
29
  export let loading: boolean = false
31
30
  export let suppressAgentPicker: boolean = false
32
- export let deletingChat: boolean = false
33
31
  export let workspaceId: string
34
32
  export let initialPrompt: string = ""
35
33
  export let userName: string = ""
36
34
 
37
35
  const dispatch = createEventDispatcher<{
38
36
  chatSaved: { chatId?: string; chat: ChatConversationLike }
39
- deleteChat: undefined
40
37
  agentSelected: { agentId: string }
41
38
  startChat: { agentId: string; prompt: string }
42
39
  }>()
@@ -83,10 +80,6 @@
83
80
 
84
81
  $: readOnlyReason = getReadOnlyReason(agentAvailability)
85
82
 
86
- const deleteChat = () => {
87
- dispatch("deleteChat")
88
- }
89
-
90
83
  const selectAgent = (agentId: string) => {
91
84
  dispatch("agentSelected", { agentId })
92
85
  }
@@ -122,32 +115,13 @@
122
115
 
123
116
  <div class="chat-wrapper">
124
117
  {#if selectedAgentId}
125
- <div class="chat-header">
126
- <div class="chat-header-agent">
127
- <Body size="S">
128
- {selectedAgentName || (loading ? "" : "Unknown agent")}
129
- </Body>
118
+ {#if hasChatId(chat)}
119
+ <div class="chat-header">
120
+ <div class="chat-header-title">
121
+ <Body size="S">{chat.title || "Untitled Chat"}</Body>
122
+ </div>
130
123
  </div>
131
-
132
- {#if hasChatId(chat)}
133
- <Button
134
- quiet
135
- warning
136
- disabled={deletingChat || loading}
137
- on:click={deleteChat}
138
- >
139
- <span class="delete-button-content">
140
- {#if deletingChat}
141
- <ProgressCircle size="S" />
142
- Deleting...
143
- {:else}
144
- <Icon name="trash" size="S" />
145
- Delete chat
146
- {/if}
147
- </span>
148
- </Button>
149
- {/if}
150
- </div>
124
+ {/if}
151
125
 
152
126
  <Chatbox
153
127
  bind:chat
@@ -161,7 +135,7 @@
161
135
  {:else if !suppressAgentPicker}
162
136
  <div class="chat-empty">
163
137
  <div class="chat-empty-greeting">
164
- <Body size="XL" weight="600" serif>
138
+ <Body size="XL" weight="600">
165
139
  {greetingText}
166
140
  </Body>
167
141
  </div>
@@ -247,12 +221,15 @@
247
221
  border-bottom: var(--border-light);
248
222
  }
249
223
 
250
- .chat-header-agent {
251
- display: flex;
252
- align-items: center;
224
+ .chat-header-title {
225
+ min-width: 0;
226
+ flex: 1 1 auto;
253
227
  }
254
228
 
255
- .chat-header-agent :global(p) {
229
+ .chat-header-title :global(p) {
230
+ overflow: hidden;
231
+ text-overflow: ellipsis;
232
+ white-space: nowrap;
256
233
  font-size: 14px;
257
234
  line-height: 17px;
258
235
  letter-spacing: 0;
@@ -260,12 +237,6 @@
260
237
  color: var(--spectrum-alias-text-color);
261
238
  }
262
239
 
263
- .delete-button-content {
264
- display: flex;
265
- align-items: center;
266
- gap: var(--spacing-xs);
267
- }
268
-
269
240
  .chat-empty {
270
241
  flex: 1 1 auto;
271
242
  display: flex;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { Body, Icon } from "@budibase/bbui"
2
+ import { ActionMenu, Body, Icon, MenuItem } from "@budibase/bbui"
3
3
  import { createEventDispatcher } from "svelte"
4
4
 
5
5
  type EnabledAgentListItem = {
@@ -15,17 +15,29 @@
15
15
  title?: string
16
16
  }
17
17
 
18
+ type ConversationWithId = ConversationListItem & {
19
+ _id: string
20
+ }
21
+
18
22
  export let enabledAgentList: EnabledAgentListItem[] = []
19
23
  export let conversationHistory: ConversationListItem[] = []
20
24
  export let selectedConversationId: string | undefined
25
+ export let selectedAgentName: string | undefined
21
26
  export let hideAgents = false
27
+ export let deletingChat = false
22
28
 
23
29
  $: defaultAgent =
24
30
  enabledAgentList.find(agent => agent.isDefault) || enabledAgentList[0]
25
31
 
32
+ $: conversationsWithId = conversationHistory.filter(
33
+ (conversation): conversation is ConversationWithId =>
34
+ Boolean(conversation._id)
35
+ )
36
+
26
37
  const dispatch = createEventDispatcher<{
27
38
  agentSelected: { agentId: string }
28
39
  conversationSelected: { conversationId: string }
40
+ conversationDeleted: { conversationId: string }
29
41
  }>()
30
42
 
31
43
  const selectAgent = (agentId: string) => {
@@ -35,10 +47,20 @@
35
47
  const selectConversation = (conversationId: string) => {
36
48
  dispatch("conversationSelected", { conversationId })
37
49
  }
50
+
51
+ const deleteConversation = (conversationId: string) => {
52
+ dispatch("conversationDeleted", { conversationId })
53
+ }
38
54
  </script>
39
55
 
40
56
  <div class="chat-nav-shell">
41
57
  <div class="chat-nav-content">
58
+ {#if selectedAgentName}
59
+ <div class="list-section current-agent-section">
60
+ <div class="current-agent-name">{selectedAgentName}</div>
61
+ </div>
62
+ {/if}
63
+
42
64
  {#if defaultAgent?.agentId}
43
65
  <div class="list-section">
44
66
  <button
@@ -78,17 +100,47 @@
78
100
 
79
101
  <div class="list-section">
80
102
  <div class="list-title">Recent Chats</div>
81
- {#if conversationHistory.length}
82
- {#each conversationHistory as conversation}
83
- {#if conversation._id}
103
+ {#if conversationsWithId.length}
104
+ {#each conversationsWithId as conversation (conversation._id)}
105
+ <div
106
+ class="conversation-row"
107
+ class:selected={selectedConversationId === conversation._id}
108
+ >
84
109
  <button
85
- class="list-item list-item-button"
86
- class:selected={selectedConversationId === conversation._id}
87
- on:click={() => selectConversation(conversation._id!)}
110
+ class="list-item list-item-button conversation-button"
111
+ on:click={() => selectConversation(conversation._id)}
88
112
  >
89
- {conversation.title || "Untitled Chat"}
113
+ <span class="conversation-title">
114
+ {conversation.title || "Untitled Chat"}
115
+ </span>
90
116
  </button>
91
- {/if}
117
+
118
+ <ActionMenu align="right" disabled={deletingChat}>
119
+ <button
120
+ slot="control"
121
+ class="conversation-actions"
122
+ type="button"
123
+ aria-label={`Open actions for ${
124
+ conversation.title || "Untitled Chat"
125
+ }`}
126
+ >
127
+ <Icon size="S" name="dots-three" />
128
+ </button>
129
+ <MenuItem
130
+ on:click={() => selectConversation(conversation._id)}
131
+ icon="chat-circle"
132
+ >
133
+ View chat
134
+ </MenuItem>
135
+ <MenuItem
136
+ on:click={() => deleteConversation(conversation._id)}
137
+ icon="trash"
138
+ disabled={deletingChat}
139
+ >
140
+ {deletingChat ? "Deleting..." : "Delete chat"}
141
+ </MenuItem>
142
+ </ActionMenu>
143
+ </div>
92
144
  {/each}
93
145
  {:else}
94
146
  <Body size="XS" color="var(--spectrum-global-color-gray-500)">
@@ -126,6 +178,17 @@
126
178
  padding-top: 0;
127
179
  }
128
180
 
181
+ .current-agent-section {
182
+ padding-bottom: var(--spacing-m);
183
+ }
184
+
185
+ .current-agent-name {
186
+ font-size: 14px;
187
+ line-height: 17px;
188
+ color: var(--spectrum-global-color-gray-800);
189
+ padding: var(--spacing-xs) 0;
190
+ }
191
+
129
192
  .new-chat {
130
193
  display: flex;
131
194
  align-items: center;
@@ -176,6 +239,59 @@
176
239
  text-overflow: ellipsis;
177
240
  }
178
241
 
242
+ .conversation-row {
243
+ display: flex;
244
+ align-items: center;
245
+ gap: var(--spacing-xxs);
246
+ min-width: 0;
247
+ }
248
+
249
+ .conversation-button {
250
+ flex: 1 1 auto;
251
+ min-width: 0;
252
+ }
253
+
254
+ .conversation-title {
255
+ overflow: hidden;
256
+ text-overflow: ellipsis;
257
+ }
258
+
259
+ .conversation-actions {
260
+ display: inline-flex;
261
+ align-items: center;
262
+ justify-content: center;
263
+ width: 24px;
264
+ height: 24px;
265
+ padding: 0;
266
+ border: none;
267
+ background: transparent;
268
+ color: var(--spectrum-global-color-gray-600);
269
+ cursor: pointer;
270
+ flex: 0 0 auto;
271
+ opacity: 0;
272
+ pointer-events: none;
273
+ transition:
274
+ opacity 120ms ease,
275
+ color 120ms ease;
276
+ }
277
+
278
+ .conversation-row:hover .conversation-actions,
279
+ .conversation-row:focus-within .conversation-actions {
280
+ opacity: 1;
281
+ pointer-events: auto;
282
+ }
283
+
284
+ .conversation-actions:hover,
285
+ .conversation-actions:focus-visible {
286
+ color: var(--spectrum-global-color-gray-900);
287
+ }
288
+
289
+ .conversation-actions:disabled {
290
+ cursor: default;
291
+ opacity: 0.5;
292
+ pointer-events: none;
293
+ }
294
+
179
295
  .list-item-icon {
180
296
  display: inline-flex;
181
297
  align-items: center;
@@ -190,11 +306,16 @@
190
306
  color: var(--spectrum-global-color-gray-900);
191
307
  }
192
308
 
193
- .list-item.selected {
309
+ .list-item.selected,
310
+ .conversation-row.selected .list-item {
194
311
  color: var(--spectrum-global-color-gray-900);
195
312
  font-weight: 600;
196
313
  }
197
314
 
315
+ .conversation-row.selected .conversation-actions {
316
+ color: var(--spectrum-global-color-gray-900);
317
+ }
318
+
198
319
  .list-title {
199
320
  font-size: 14px;
200
321
  line-height: 17px;
@@ -806,6 +806,14 @@
806
806
  flex-direction: column;
807
807
  overflow-y: auto;
808
808
  min-height: 0;
809
+ font-family: var(--chat-font-sans, var(--font-sans));
810
+ --font-serif: var(--chat-font-sans, var(--font-sans));
811
+ --font-accent: var(--chat-font-sans, var(--font-sans));
812
+ --spectrum-alias-body-text-font-family: var(
813
+ --chat-font-sans,
814
+ var(--font-sans)
815
+ );
816
+ --spectrum-global-font-family-base: var(--chat-font-sans, var(--font-sans));
809
817
  }
810
818
  .chatbox {
811
819
  display: flex;