@meistrari/chat-nuxt 4.4.0-rc.0 → 4.4.0-rc.10
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/README.md +15 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +6 -0
- package/dist/runtime/conversations/components/chat-conversation-item.vue +50 -69
- package/dist/runtime/conversations/components/chat-conversation-list.vue +84 -61
- package/dist/runtime/conversations/composables/conversation-item.js +4 -0
- package/dist/runtime/conversations/composables/conversation-list.d.ts +2 -0
- package/dist/runtime/conversations/composables/conversation-list.js +33 -4
- package/dist/runtime/conversations/composables/conversations.js +2 -1
- package/dist/runtime/embed/components/chat-embed-inner.d.vue.ts +13 -2
- package/dist/runtime/embed/components/chat-embed-inner.vue +140 -88
- package/dist/runtime/embed/components/chat-embed-inner.vue.d.ts +13 -2
- package/dist/runtime/embed/components/chat-embed.d.vue.ts +6 -46
- package/dist/runtime/embed/components/chat-embed.vue +51 -9
- package/dist/runtime/embed/components/chat-embed.vue.d.ts +6 -46
- package/dist/runtime/embed/components/chat-topbar.d.vue.ts +11 -1
- package/dist/runtime/embed/components/chat-topbar.vue +7 -8
- package/dist/runtime/embed/components/chat-topbar.vue.d.ts +11 -1
- package/dist/runtime/embed/components/meistrari-chat-embed.d.vue.ts +2 -0
- package/dist/runtime/embed/components/meistrari-chat-embed.vue +9 -3
- package/dist/runtime/embed/components/meistrari-chat-embed.vue.d.ts +2 -0
- package/dist/runtime/embed/components/mobile/chat-mobile-drawer.vue +0 -1
- package/dist/runtime/embed/components/mobile/chat-mobile-shell.d.vue.ts +2 -2
- package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue.d.ts +2 -2
- package/dist/runtime/embed/composables/agent-harness.d.ts +15 -0
- package/dist/runtime/embed/composables/agent-harness.js +55 -0
- package/dist/runtime/embed/composables/conversation-browser-state.d.ts +1 -1
- package/dist/runtime/embed/composables/conversation-browser-state.js +5 -3
- package/dist/runtime/embed/composables/embed-config.d.ts +4 -5
- package/dist/runtime/embed/composables/harness-adapter.d.ts +14 -0
- package/dist/runtime/embed/composables/harness-adapter.js +8 -0
- package/dist/runtime/embed/types.d.ts +10 -7
- package/dist/runtime/files/composables/file-drop.d.ts +2 -8
- package/dist/runtime/files/composables/file-drop.js +3 -31
- package/dist/runtime/files/composables/file-upload.js +46 -15
- package/dist/runtime/lightweight/embed/components/chat-embed-adapter.d.vue.ts +13 -0
- package/dist/runtime/lightweight/embed/components/chat-embed-adapter.vue +20 -0
- package/dist/runtime/lightweight/embed/components/chat-embed-adapter.vue.d.ts +13 -0
- package/dist/runtime/lightweight/embed/composables/model-selection.d.ts +5 -0
- package/dist/runtime/lightweight/embed/composables/model-selection.js +29 -0
- package/dist/runtime/lightweight/messages/composables/chat-model-catalog.d.ts +10 -0
- package/dist/runtime/lightweight/messages/composables/chat-model-catalog.js +55 -0
- package/dist/runtime/lightweight/messages/composables/chat.d.ts +42 -0
- package/dist/runtime/lightweight/messages/composables/chat.js +10 -0
- package/dist/runtime/lightweight/messages/composables/use-direct-stream.d.ts +34 -0
- package/dist/runtime/lightweight/messages/composables/use-direct-stream.js +22 -0
- package/dist/runtime/lightweight/messages/model-options.d.ts +27 -0
- package/dist/runtime/lightweight/messages/model-options.js +40 -0
- package/dist/runtime/messages/answer.d.ts +23 -0
- package/dist/runtime/messages/answer.js +42 -0
- package/dist/runtime/messages/components/chat-answer.d.vue.ts +14 -0
- package/dist/runtime/messages/components/chat-answer.vue +154 -0
- package/dist/runtime/messages/components/chat-answer.vue.d.ts +14 -0
- package/dist/runtime/messages/components/chat-context-config.vue +4 -17
- package/dist/runtime/messages/components/chat-message-bubble.vue +25 -1
- package/dist/runtime/messages/components/chat-message-input.vue +155 -162
- package/dist/runtime/messages/components/chat-message-list.d.vue.ts +2 -2
- package/dist/runtime/messages/components/chat-message-list.vue +10 -11
- package/dist/runtime/messages/components/chat-message-list.vue.d.ts +2 -2
- package/dist/runtime/messages/components/chat-model-selector.vue +13 -1
- package/dist/runtime/messages/components/chat-reasoning-effort-selector.vue +11 -7
- package/dist/runtime/messages/components/reasoning/chat-reasoning-thought.vue +1 -1
- package/dist/runtime/messages/components/reasoning/chat-thinking-indicator.d.vue.ts +4 -1
- package/dist/runtime/messages/components/reasoning/chat-thinking-indicator.vue +15 -3
- package/dist/runtime/messages/components/reasoning/chat-thinking-indicator.vue.d.ts +4 -1
- package/dist/runtime/messages/components/widgets/chat-tool-section.d.vue.ts +1 -1
- package/dist/runtime/messages/components/widgets/chat-tool-section.vue.d.ts +1 -1
- package/dist/runtime/messages/composables/chat-message-terminal.d.ts +1 -0
- package/dist/runtime/messages/composables/chat-message-terminal.js +2 -1
- package/dist/runtime/messages/composables/chat.d.ts +15 -3
- package/dist/runtime/messages/composables/chat.js +17 -6
- package/dist/runtime/messages/composables/use-direct-stream.d.ts +35 -2
- package/dist/runtime/messages/composables/use-direct-stream.js +17 -3
- package/dist/runtime/messages/model-availability.d.ts +5 -3
- package/dist/runtime/messages/model-availability.js +13 -6
- package/dist/runtime/rendering/components/app-markdown-render.vue +1 -7
- package/dist/runtime/rendering/markdown/escape-dollar-signs.d.ts +1 -0
- package/dist/runtime/rendering/markdown/escape-dollar-signs.js +7 -0
- package/dist/runtime/shared/composables/chat-request-context.d.ts +3 -0
- package/dist/runtime/shared/composables/chat-request-context.js +4 -0
- package/dist/runtime/types/messages.d.ts +2 -0
- package/dist/runtime/types/messages.js +1 -0
- package/dist/runtime/types/schemas/chat/chat-config.d.ts +6 -0
- package/dist/runtime/types/schemas/chat/chat-config.js +3 -0
- package/dist/runtime/types/schemas/chat/conversation-runtime.d.ts +2 -0
- package/dist/runtime/types/schemas/chat/conversation-runtime.js +1 -1
- package/dist/runtime/types/schemas/chat/conversations.d.ts +38 -0
- package/dist/runtime/types/schemas/chat/conversations.js +9 -0
- package/dist/runtime/types/schemas/chat/lightweight-models.d.ts +126 -0
- package/dist/runtime/types/schemas/chat/lightweight-models.js +34 -0
- package/dist/runtime/types/schemas/chat/models.d.ts +2 -1
- package/dist/runtime/types/schemas/chat/models.js +1 -0
- package/dist/runtime/types/schemas/chat/ui.d.ts +10 -0
- package/dist/runtime/types/schemas/chat/ui.js +1 -0
- package/dist/runtime/types/schemas/chat/usage.d.ts +0 -15
- package/dist/runtime/types/schemas/chat/usage.js +0 -3
- package/dist/runtime/types/schemas/index.d.ts +3 -0
- package/dist/runtime/types/schemas/index.js +2 -0
- package/dist/runtime/types/schemas/integrations/lightweight.d.ts +17 -0
- package/dist/runtime/types/schemas/integrations/lightweight.js +135 -0
- package/dist/runtime/types/schemas/integrations/tela-agent-api.d.ts +1 -0
- package/dist/runtime/usage/formatting.js +2 -3
- package/package.json +7 -2
- package/dist/runtime/files/file-limits.d.ts +0 -2
- package/dist/runtime/files/file-limits.js +0 -2
package/README.md
CHANGED
|
@@ -33,6 +33,20 @@ Runtime internals under `src/runtime/**`, generated Nuxt aliases, and workspace-
|
|
|
33
33
|
| [Workspace settings](docs/guides/workspace-settings.md) | Settings overrides, agent runtime ownership, `<ChatConfigurationModal>` |
|
|
34
34
|
| [Upgrading to 4.0](docs/guides/upgrading-to-4.md) | Required Chat API version for v2 sends, upgrade order, vue-i18n removal |
|
|
35
35
|
|
|
36
|
+
## Harness selection
|
|
37
|
+
|
|
38
|
+
Select the Tela agent; its published `agent.config.json` determines the harness:
|
|
39
|
+
|
|
40
|
+
```vue
|
|
41
|
+
<MeistrariChatEmbed tela-agent-id="your-agent-id" />
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The chat resolves the agent before mounting its UI. Explicit branches use that branch's configuration. Missing, unreadable or unsupported harnesses show an error and never fall back to Claude. The host cannot select a harness through props or HTTP headers.
|
|
45
|
+
|
|
46
|
+
Both harnesses share the chat screen, composer, navigation and state controller, while their protocol adapters and renderers remain separate. Selecting another agent clears the old UI and resolves its configuration again. The backend independently reads the configured harness for routed requests.
|
|
47
|
+
|
|
48
|
+
Requires Agent API v4’s `GET /v4/agents/{organizationName}/{repository}/harness` endpoint. Chat resolves the existing agent coordinates, then reads the configured harness directly from Agent API using the published commit or selected branch. The response exposes only the harness. Deploy the Agent API endpoint before this Chat version; no Tela API changes are required.
|
|
49
|
+
|
|
36
50
|
## Conversation forks
|
|
37
51
|
|
|
38
52
|
Completed assistant responses offer **Continuar em nova conversa** in the three-dot
|
|
@@ -74,7 +88,7 @@ Declared in `src/runtime/embed/types.ts`; prop, feature-flag, and event payload
|
|
|
74
88
|
| `initialConversationId` | `string \| null` | `null` | Conversation to open once on mount when `conversationId` is uncontrolled |
|
|
75
89
|
| `conversationScope` | `string \| null` | `null` | Isolate conversation history by technical scope within the current workspace and runtime. Scoped embeds only see same-scope conversations; values are trimmed, blank becomes `null`, and the server accepts 1-200 chars from `A-Z`, `a-z`, `0-9`, `.`, `_`, `:`, `/`, `-` |
|
|
76
90
|
| `defaultConversationCreatorFilter` | `'all' \| 'mine'` | `'all'` | Initial sidebar creator filter: every conversation in scope, or only the current user's |
|
|
77
|
-
| `availableModels` | `AvailableChatModels` |
|
|
91
|
+
| `availableModels` | `AvailableChatModels` | Workspace catalog | Optional non-empty ordered subset of models served for the active workspace. Unknown ids fail at runtime; a restored unavailable selection stays visible and blocked until the user chooses an available model |
|
|
78
92
|
| `defaultModel` | `ChatModel` | Package default | Initial model for untouched drafts. Explicit selections and existing conversations take precedence; `availableModels` still limits the selection |
|
|
79
93
|
| `defaultReasoningEffort` | `ChatReasoningEffort` | Automatic (`null`) | Initial reasoning effort for untouched drafts. Explicit user choices (including automatic) take precedence |
|
|
80
94
|
| `conversationCreatorFilter` | `'all' \| 'mine'` | — | Controlled sidebar creator filter; use with `v-model:conversation-creator-filter` when the host changes it at runtime |
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -190,7 +190,12 @@ const FULL_NAME_COMPONENT_DIRS = ["citations", "conversations", "embed", "files"
|
|
|
190
190
|
const PATH_PREFIX_COMPONENT_DIRS = ["rendering", "shared"];
|
|
191
191
|
const DYNAMIC_ICON_SAFELIST = [
|
|
192
192
|
"i-ph-folder-minus",
|
|
193
|
+
// Folder actions menu (conversation-list.ts).
|
|
194
|
+
"i-ph-folder-minus-bold",
|
|
193
195
|
"i-ph-folder-open",
|
|
196
|
+
// Sidebar folder rows build their icon name in conversation-list.ts.
|
|
197
|
+
"i-ph-folder-notch",
|
|
198
|
+
"i-ph-folder-notch-open",
|
|
194
199
|
// Neutral pill icon for host-defined user mentions (user-mentions.ts).
|
|
195
200
|
"i-ph-paperclip"
|
|
196
201
|
];
|
|
@@ -445,6 +450,7 @@ const module$1 = defineNuxtModule({
|
|
|
445
450
|
const rc = nuxt.options.runtimeConfig;
|
|
446
451
|
rc.chatApiUrl = options.chatApiUrl || rc.chatApiUrl || process.env.CHAT_API_URL || "";
|
|
447
452
|
rc.public = rc.public || {};
|
|
453
|
+
rc.public.chatConfig = { ...rc.public.chatConfig };
|
|
448
454
|
const existingChatNuxtRuntimeConfig = rc.chatNuxt;
|
|
449
455
|
rc.chatNuxt = {
|
|
450
456
|
chatApiUrl: existingChatNuxtRuntimeConfig?.chatApiUrl || rc.chatApiUrl,
|
|
@@ -33,23 +33,37 @@ function setRenameInputRef(element) {
|
|
|
33
33
|
</script>
|
|
34
34
|
|
|
35
35
|
<template>
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
<a
|
|
37
|
+
:href="conversationPath"
|
|
38
|
+
:draggable="draggable && !isRenamingInline"
|
|
39
|
+
block
|
|
40
|
+
pl-12px pr-4px
|
|
41
|
+
h-30px
|
|
42
|
+
rounded-8px
|
|
43
|
+
class="group data-[active=true]:bg-muted data-[active=false]:hover:bg-subtle"
|
|
44
|
+
:class="isRenamingInline ? '' : 'cursor-pointer'"
|
|
45
|
+
:data-active="active"
|
|
46
|
+
@click="handleConversationClick"
|
|
47
|
+
@dblclick.prevent.stop="startRename"
|
|
48
|
+
@dragstart="handleConversationDragStart"
|
|
49
|
+
@dragend="handleConversationDragEnd"
|
|
42
50
|
>
|
|
43
|
-
<div flex items-center justify-between
|
|
44
|
-
|
|
51
|
+
<div flex items-center justify-between h-full :class="props.itemClass">
|
|
52
|
+
<!-- User Avatar -->
|
|
53
|
+
<div
|
|
54
|
+
v-if="userImage"
|
|
55
|
+
translate-x--48px w-0 opacity-0 shrink-0 overflow-hidden
|
|
56
|
+
class="[transition:width_0.26s_cubic-bezier(0.22,1,0.36,1),transform_0.26s_cubic-bezier(0.22,1,0.36,1),opacity_0.2s] group-hover:w-22px group-hover:translate-x-0 group-hover:opacity-100"
|
|
57
|
+
>
|
|
45
58
|
<TelaAvatar
|
|
46
59
|
:image="userImage"
|
|
47
60
|
alt="Usuário"
|
|
48
61
|
size="2xs"
|
|
62
|
+
class="rounded-full!"
|
|
49
63
|
/>
|
|
50
64
|
</div>
|
|
51
65
|
|
|
52
|
-
<div relative flex-1 min-w-0 flex items-center>
|
|
66
|
+
<div v-if="isRenamingInline" relative flex-1 min-w-0 flex items-center>
|
|
53
67
|
<input
|
|
54
68
|
:ref="setRenameInputRef"
|
|
55
69
|
v-model="renameTitle"
|
|
@@ -58,7 +72,7 @@ function setRenameInputRef(element) {
|
|
|
58
72
|
aria-label="Nome da conversa"
|
|
59
73
|
w-full min-w-0
|
|
60
74
|
bg-transparent border-none outline-none
|
|
61
|
-
body-14-medium text-
|
|
75
|
+
body-14-medium text-taupe-600
|
|
62
76
|
p-0
|
|
63
77
|
@blur="handleRenameBlur"
|
|
64
78
|
@keydown.enter.prevent="submitRename"
|
|
@@ -66,69 +80,36 @@ function setRenameInputRef(element) {
|
|
|
66
80
|
>
|
|
67
81
|
<div aria-hidden="true" absolute inset-x-0 bottom--0.5px h-0.5px bg-border pointer-events-none />
|
|
68
82
|
</div>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
83
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
:data-active="active"
|
|
83
|
-
@click="handleConversationClick"
|
|
84
|
-
@dblclick.prevent.stop="startRename"
|
|
85
|
-
@dragstart="handleConversationDragStart"
|
|
86
|
-
@dragend="handleConversationDragEnd"
|
|
87
|
-
>
|
|
88
|
-
<div flex items-center justify-between gap-8px h-full :class="props.itemClass">
|
|
89
|
-
<!-- User Avatar -->
|
|
90
|
-
<div v-if="userImage" w-16px h-16px flex items-center justify-center rounded-full overflow-hidden flex-shrink-0>
|
|
91
|
-
<TelaAvatar
|
|
92
|
-
:image="userImage"
|
|
93
|
-
alt="Usuário"
|
|
94
|
-
size="2xs"
|
|
95
|
-
/>
|
|
96
|
-
</div>
|
|
84
|
+
<template v-else>
|
|
85
|
+
<div flex-1 min-w-0 flex items-center>
|
|
86
|
+
<span
|
|
87
|
+
body-14-medium
|
|
88
|
+
text-taupe-700
|
|
89
|
+
truncate
|
|
90
|
+
>
|
|
91
|
+
{{ displayTitle }}
|
|
92
|
+
</span>
|
|
93
|
+
</div>
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
class="group-hover:text-primary group-data-[active=true]:text-primary"
|
|
103
|
-
truncate
|
|
95
|
+
<div
|
|
96
|
+
flex
|
|
97
|
+
items-center
|
|
98
|
+
class="opacity-0 group-hover:opacity-100 focus-within:opacity-100 [&:has([data-state=open])]:opacity-100"
|
|
104
99
|
>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
>
|
|
115
|
-
<TelaDropdownMenu :items="menuItems" content-class="chat-sidebar-floating">
|
|
116
|
-
<button
|
|
117
|
-
p-4px
|
|
118
|
-
rounded-8px
|
|
119
|
-
hover:bg-lowered
|
|
120
|
-
cursor-pointer
|
|
121
|
-
class="group data-[state=open]:!bg-lowered"
|
|
122
|
-
@click.prevent.stop
|
|
123
|
-
>
|
|
124
|
-
<TelaIcon
|
|
125
|
-
name="i-ph-dots-three"
|
|
126
|
-
size="18px"
|
|
127
|
-
color="icon-subtle group-hover:icon-tertiary group-data-[state=open]:icon-tertiary"
|
|
100
|
+
<TelaDropdownMenu :items="menuItems" content-class="chat-sidebar-floating">
|
|
101
|
+
<TelaIconButton
|
|
102
|
+
icon="i-ph-dots-three"
|
|
103
|
+
color="secondary"
|
|
104
|
+
size="3xs"
|
|
105
|
+
aria-label="Ações da conversa"
|
|
106
|
+
class="group hover:!bg-lowered data-[state=open]:!bg-lowered"
|
|
107
|
+
icon-class="group-hover:icon-tertiary group-data-[state=open]:icon-tertiary"
|
|
108
|
+
@click.prevent.stop
|
|
128
109
|
/>
|
|
129
|
-
</
|
|
130
|
-
</
|
|
131
|
-
</
|
|
110
|
+
</TelaDropdownMenu>
|
|
111
|
+
</div>
|
|
112
|
+
</template>
|
|
132
113
|
</div>
|
|
133
114
|
</a>
|
|
134
115
|
|
|
@@ -47,29 +47,37 @@ const {
|
|
|
47
47
|
handleDragLeave,
|
|
48
48
|
getConversationItemProps,
|
|
49
49
|
handleConversationDrop,
|
|
50
|
-
startConversationInGroup
|
|
50
|
+
startConversationInGroup,
|
|
51
|
+
startUngroupedConversation,
|
|
52
|
+
createNewGroup
|
|
51
53
|
} = useConversationList(props);
|
|
54
|
+
const ROW_HEIGHT = 32;
|
|
55
|
+
const HEADING_HEIGHT = 28;
|
|
56
|
+
const ERROR_ROW_HEIGHT = 20;
|
|
57
|
+
const SECTION_GAP = 10;
|
|
52
58
|
const rows = computed(() => {
|
|
53
59
|
const result = [];
|
|
54
60
|
if (groupItems.value.length > 0)
|
|
55
|
-
result.push({ type: "folders", key: "folders", height:
|
|
61
|
+
result.push({ type: "folders", key: "folders", height: HEADING_HEIGHT, groupId: null });
|
|
56
62
|
for (const groupBucket of groupItems.value) {
|
|
57
63
|
const groupId = groupBucket.group.id;
|
|
58
|
-
result.push({ type: "group", key: `group:${groupId}`, height:
|
|
64
|
+
result.push({ type: "group", key: `group:${groupId}`, height: ROW_HEIGHT, groupId, groupBucket });
|
|
59
65
|
if (groupBucket.isRenaming && renameGroupError.value)
|
|
60
|
-
result.push({ type: "error", key: `error:${groupId}`, height:
|
|
66
|
+
result.push({ type: "error", key: `error:${groupId}`, height: ERROR_ROW_HEIGHT, groupId, groupBucket });
|
|
61
67
|
if (!groupBucket.open)
|
|
62
68
|
continue;
|
|
63
69
|
for (const conversation of groupBucket.items)
|
|
64
|
-
result.push({ type: "conversation", key: conversation.id, height:
|
|
70
|
+
result.push({ type: "conversation", key: conversation.id, height: ROW_HEIGHT, groupId, conversation });
|
|
65
71
|
if (groupBucket.showNewConversationAction)
|
|
66
|
-
result.push({ type: "new", key: `new:${groupId}`, height:
|
|
72
|
+
result.push({ type: "new", key: `new:${groupId}`, height: ROW_HEIGHT, groupId, groupBucket });
|
|
67
73
|
else if (groupBucket.showSearchEmpty)
|
|
68
|
-
result.push({ type: "empty", key: `empty:${groupId}`, height:
|
|
74
|
+
result.push({ type: "empty", key: `empty:${groupId}`, height: ROW_HEIGHT, groupId, groupBucket });
|
|
69
75
|
}
|
|
70
|
-
|
|
76
|
+
if (groupItems.value.length > 0)
|
|
77
|
+
result.push({ type: "spacer", key: "spacer", height: SECTION_GAP, groupId: null });
|
|
78
|
+
result.push({ type: "ungrouped", key: "ungrouped", height: HEADING_HEIGHT, groupId: null });
|
|
71
79
|
for (const conversation of ungroupedConversations.value)
|
|
72
|
-
result.push({ type: "conversation", key: conversation.id, height:
|
|
80
|
+
result.push({ type: "conversation", key: conversation.id, height: ROW_HEIGHT, groupId: null, conversation });
|
|
73
81
|
let offset = 0;
|
|
74
82
|
return result.map((row) => {
|
|
75
83
|
const positionedRow = { ...row, offset };
|
|
@@ -117,7 +125,7 @@ async function handleRowKeydown(event, index) {
|
|
|
117
125
|
return;
|
|
118
126
|
const direction = event.shiftKey ? -1 : 1;
|
|
119
127
|
let nextIndex = index + direction;
|
|
120
|
-
while (rows.value[nextIndex] && ["folders", "ungrouped", "empty", "error"].includes(rows.value[nextIndex].type))
|
|
128
|
+
while (rows.value[nextIndex] && ["folders", "spacer", "ungrouped", "empty", "error"].includes(rows.value[nextIndex].type))
|
|
121
129
|
nextIndex += direction;
|
|
122
130
|
const nextRow = rows.value[nextIndex];
|
|
123
131
|
if (!nextRow)
|
|
@@ -132,7 +140,7 @@ async function handleRowKeydown(event, index) {
|
|
|
132
140
|
}
|
|
133
141
|
watch(conversationSearch, () => scrollTo(0), { flush: "post" });
|
|
134
142
|
function acceptsDrops(row) {
|
|
135
|
-
return row.type !== "folders";
|
|
143
|
+
return row.type !== "folders" && row.type !== "spacer";
|
|
136
144
|
}
|
|
137
145
|
function dropListeners(row) {
|
|
138
146
|
if (!acceptsDrops(row))
|
|
@@ -153,6 +161,13 @@ function dropListeners(row) {
|
|
|
153
161
|
}
|
|
154
162
|
};
|
|
155
163
|
}
|
|
164
|
+
function isNestedRow(row) {
|
|
165
|
+
return Boolean(row.groupId) && (row.type === "conversation" || row.type === "new" || row.type === "empty");
|
|
166
|
+
}
|
|
167
|
+
function isLastNestedRow(index) {
|
|
168
|
+
const next = rows.value[index + 1];
|
|
169
|
+
return !next || !isNestedRow(next) || next.groupId !== rows.value[index].groupId;
|
|
170
|
+
}
|
|
156
171
|
function dropTargetClass(row) {
|
|
157
172
|
if (!acceptsDrops(row))
|
|
158
173
|
return "";
|
|
@@ -163,10 +178,9 @@ function dropTargetClass(row) {
|
|
|
163
178
|
</script>
|
|
164
179
|
|
|
165
180
|
<template>
|
|
166
|
-
<div flex="~ col" gap-
|
|
167
|
-
<div px-8px
|
|
181
|
+
<div flex="~ col" gap-6px h-full min-h-0 overflow-hidden>
|
|
182
|
+
<div px-8px shrink-0>
|
|
168
183
|
<ChatConversationSearch v-model="conversationSearch" />
|
|
169
|
-
<ChatConversationCreatorFilter />
|
|
170
184
|
</div>
|
|
171
185
|
|
|
172
186
|
<div v-if="shouldShowSkeleton" flex="~ col" gap-4px>
|
|
@@ -208,19 +222,41 @@ function dropTargetClass(row) {
|
|
|
208
222
|
@dragend.capture="draggedRowKey = null"
|
|
209
223
|
v-on="dropListeners(row)"
|
|
210
224
|
>
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
225
|
+
<div v-if="row.type === 'folders'" h-full flex items-center justify-between pl-12px pr-2px>
|
|
226
|
+
<span body-12-medium text-tertiary>
|
|
227
|
+
Pastas
|
|
228
|
+
</span>
|
|
229
|
+
<TelaIconButton
|
|
230
|
+
icon="i-ph-plus"
|
|
231
|
+
color="secondary"
|
|
232
|
+
size="sm"
|
|
233
|
+
button-class="p-3px! rounded-6px!"
|
|
234
|
+
aria-label="Nova pasta"
|
|
235
|
+
@click="createNewGroup"
|
|
236
|
+
/>
|
|
237
|
+
</div>
|
|
238
|
+
<div v-else-if="row.type === 'ungrouped'" h-full flex items-center justify-between pl-12px pr-2px>
|
|
239
|
+
<span body-12-medium text-secondary>
|
|
240
|
+
{{ ungroupedConversationLabel }}
|
|
241
|
+
</span>
|
|
242
|
+
<TelaIconButton
|
|
243
|
+
icon="i-ph-plus"
|
|
244
|
+
color="secondary"
|
|
245
|
+
size="sm"
|
|
246
|
+
button-class="p-3px! rounded-6px!"
|
|
247
|
+
aria-label="Nova conversa"
|
|
248
|
+
@click="startUngroupedConversation"
|
|
249
|
+
/>
|
|
250
|
+
</div>
|
|
217
251
|
<div
|
|
218
252
|
v-if="row.type === 'group'"
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
253
|
+
pl-12px pr-4px
|
|
254
|
+
h-30px
|
|
255
|
+
rounded-8px
|
|
256
|
+
class="group hover:bg-subtle"
|
|
257
|
+
:data-active="row.groupBucket.open && !row.groupBucket.dropTarget"
|
|
222
258
|
>
|
|
223
|
-
<div
|
|
259
|
+
<div flex items-center justify-between h-full gap-8px>
|
|
224
260
|
<template v-if="row.groupBucket.isRenaming">
|
|
225
261
|
<TelaIcon
|
|
226
262
|
:name="row.groupBucket.folderIcon"
|
|
@@ -228,11 +264,7 @@ function dropTargetClass(row) {
|
|
|
228
264
|
color="icon-secondary"
|
|
229
265
|
shrink-0
|
|
230
266
|
/>
|
|
231
|
-
<div
|
|
232
|
-
relative
|
|
233
|
-
flex-1 min-w-0 flex items-center
|
|
234
|
-
mr-4px
|
|
235
|
-
>
|
|
267
|
+
<div relative flex-1 min-w-0 flex items-center>
|
|
236
268
|
<input
|
|
237
269
|
:ref="(element) => setRenameGroupInputRef(element, row.groupBucket.group.id)"
|
|
238
270
|
v-model="renameGroupName"
|
|
@@ -242,7 +274,7 @@ function dropTargetClass(row) {
|
|
|
242
274
|
aria-label="Nome da pasta"
|
|
243
275
|
w-full min-w-0
|
|
244
276
|
bg-transparent border-none outline-none
|
|
245
|
-
body-14-medium text-
|
|
277
|
+
body-14-medium text-taupe-600
|
|
246
278
|
p-0
|
|
247
279
|
:disabled="groupActionLoading"
|
|
248
280
|
@blur="handleRenameGroupBlur"
|
|
@@ -253,7 +285,7 @@ function dropTargetClass(row) {
|
|
|
253
285
|
>
|
|
254
286
|
<div
|
|
255
287
|
aria-hidden="true"
|
|
256
|
-
absolute inset-x-0 bottom--
|
|
288
|
+
absolute inset-x-0 bottom--0.5px h-0.5px pointer-events-none
|
|
257
289
|
:class="renameGroupError ? 'bg-red-500' : 'bg-border'"
|
|
258
290
|
/>
|
|
259
291
|
</div>
|
|
@@ -272,41 +304,31 @@ function dropTargetClass(row) {
|
|
|
272
304
|
<TelaIcon
|
|
273
305
|
:name="row.groupBucket.folderIcon"
|
|
274
306
|
size="16px"
|
|
275
|
-
color="icon-
|
|
307
|
+
color="icon-tertiary"
|
|
276
308
|
shrink-0
|
|
277
309
|
/>
|
|
278
|
-
<
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
</span>
|
|
282
|
-
<TelaAnimatedNumber v-if="row.groupBucket.conversationCountLabel" :value="row.groupBucket.conversationCountLabel" body-12-medium text-tertiary />
|
|
283
|
-
</div>
|
|
310
|
+
<span min-w-0 truncate body-14-medium text-taupe-700>
|
|
311
|
+
{{ row.groupBucket.group.name }}
|
|
312
|
+
</span>
|
|
284
313
|
</button>
|
|
285
314
|
|
|
286
315
|
<div
|
|
287
|
-
flex items-center
|
|
316
|
+
flex items-center
|
|
288
317
|
class="opacity-0 group-hover:opacity-100 focus-within:opacity-100 [&:has([data-state=open])]:opacity-100"
|
|
289
318
|
>
|
|
290
319
|
<TelaDropdownMenu
|
|
291
320
|
:items="row.groupBucket.menuItems"
|
|
292
321
|
content-class="chat-sidebar-floating"
|
|
293
322
|
>
|
|
294
|
-
<
|
|
295
|
-
|
|
323
|
+
<TelaIconButton
|
|
324
|
+
icon="i-ph-dots-three"
|
|
325
|
+
color="secondary"
|
|
326
|
+
size="3xs"
|
|
296
327
|
aria-label="Ações da pasta"
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
hover:bg-lowered
|
|
300
|
-
cursor-pointer
|
|
301
|
-
class="group data-[state=open]:!bg-lowered"
|
|
328
|
+
class="group hover:!bg-lowered data-[state=open]:!bg-lowered"
|
|
329
|
+
icon-class="group-hover:icon-tertiary group-data-[state=open]:icon-tertiary"
|
|
302
330
|
@click.prevent.stop
|
|
303
|
-
|
|
304
|
-
<TelaIcon
|
|
305
|
-
name="i-ph-dots-three"
|
|
306
|
-
size="18px"
|
|
307
|
-
color="icon-subtle group-hover:icon-tertiary group-data-[state=open]:icon-tertiary"
|
|
308
|
-
/>
|
|
309
|
-
</button>
|
|
331
|
+
/>
|
|
310
332
|
</TelaDropdownMenu>
|
|
311
333
|
</div>
|
|
312
334
|
</template>
|
|
@@ -332,25 +354,26 @@ function dropTargetClass(row) {
|
|
|
332
354
|
<button
|
|
333
355
|
v-if="row.type === 'new'"
|
|
334
356
|
type="button"
|
|
335
|
-
h-
|
|
336
|
-
flex items-center
|
|
337
|
-
rounded-
|
|
357
|
+
relative h-30px pl-12px w-full
|
|
358
|
+
flex items-center justify-between
|
|
359
|
+
rounded-8px
|
|
338
360
|
text-left
|
|
339
361
|
hover:bg-subtle
|
|
340
362
|
cursor-pointer
|
|
341
363
|
@click="startConversationInGroup(row.groupBucket.group.id)"
|
|
342
364
|
>
|
|
343
|
-
<span body-14-medium text-
|
|
365
|
+
<span body-14-medium text-taupe-500 ml-24px>
|
|
344
366
|
Nova conversa
|
|
345
367
|
</span>
|
|
346
|
-
<TelaIcon name="i-ph-plus" size="14px" color="icon-secondary" shrink-0 />
|
|
347
368
|
</button>
|
|
348
|
-
<div v-if="row.type === 'empty'" h-
|
|
369
|
+
<div v-if="row.type === 'empty'" h-full flex items-center ml-36px>
|
|
349
370
|
<span body-14-medium text-tertiary>Sem resultados</span>
|
|
350
371
|
</div>
|
|
351
372
|
<div
|
|
352
|
-
v-if="
|
|
353
|
-
aria-hidden="true"
|
|
373
|
+
v-if="isNestedRow(row)"
|
|
374
|
+
aria-hidden="true"
|
|
375
|
+
absolute top-0 left-19px w-0.5px bg-border pointer-events-none
|
|
376
|
+
:class="isLastNestedRow(row.index) ? 'h-30px' : 'h-full'"
|
|
354
377
|
/>
|
|
355
378
|
</div>
|
|
356
379
|
</div>
|
|
@@ -55,6 +55,10 @@ export function useConversationItem(options, emit) {
|
|
|
55
55
|
showDeleteModal.value = false;
|
|
56
56
|
}
|
|
57
57
|
function handleConversationClick(event) {
|
|
58
|
+
if (isRenamingInline.value) {
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
58
62
|
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
|
|
59
63
|
return;
|
|
60
64
|
event.preventDefault();
|
|
@@ -123,4 +123,6 @@ export declare function useConversationList(options: ConversationListOptions): {
|
|
|
123
123
|
};
|
|
124
124
|
handleConversationDrop: (event: DragEvent, groupId: string | null) => Promise<void>;
|
|
125
125
|
startConversationInGroup: (groupId: string) => void;
|
|
126
|
+
startUngroupedConversation: () => void;
|
|
127
|
+
createNewGroup: () => Promise<void>;
|
|
126
128
|
};
|
|
@@ -15,7 +15,7 @@ export function useConversationList(options) {
|
|
|
15
15
|
const embedConfig = useEmbedConfig();
|
|
16
16
|
const { activeOrganization } = useChatAuth();
|
|
17
17
|
const { deleteConversation, renameConversation, duplicateConversation, moveConversationToGroup } = useConversations();
|
|
18
|
-
const { groups, fetchGroups, deleteGroup, renameGroup, error: groupError, pendingRenameGroupId } = useConversationGroups();
|
|
18
|
+
const { groups, fetchGroups, createGroup, deleteGroup, renameGroup, error: groupError, pendingRenameGroupId } = useConversationGroups();
|
|
19
19
|
const { setConversation } = useChat();
|
|
20
20
|
const route = useRoute();
|
|
21
21
|
const router = useRouter();
|
|
@@ -239,7 +239,7 @@ export function useConversationList(options) {
|
|
|
239
239
|
...groupBucket,
|
|
240
240
|
open,
|
|
241
241
|
dropTarget,
|
|
242
|
-
folderIcon: open ? "i-ph-folder-notch-open
|
|
242
|
+
folderIcon: open ? "i-ph-folder-notch-open" : "i-ph-folder-notch",
|
|
243
243
|
isRenaming: renamingGroupId.value === groupBucket.group.id,
|
|
244
244
|
conversationCountLabel: groupBucket.items.length > 0 ? String(groupBucket.items.length) : null,
|
|
245
245
|
showNewConversationAction: !hasConversationSearchQuery.value,
|
|
@@ -249,7 +249,7 @@ export function useConversationList(options) {
|
|
|
249
249
|
}));
|
|
250
250
|
const ungroupedConversations = computed(() => groupedConversations.value.unfiled);
|
|
251
251
|
const ungroupedDropTarget = computed(() => isDropTarget(null));
|
|
252
|
-
const ungroupedConversationLabel = computed(() => `Conversas
|
|
252
|
+
const ungroupedConversationLabel = computed(() => `Conversas`);
|
|
253
253
|
const shouldShowUngroupedHeader = computed(() => groupItems.value.length > 0);
|
|
254
254
|
const showGroupCreationPrompt = computed(
|
|
255
255
|
() => groupsReady.value && !hasConversationSearchQuery.value && groups.value.length === 0
|
|
@@ -496,6 +496,33 @@ export function useConversationList(options) {
|
|
|
496
496
|
return;
|
|
497
497
|
await moveConversationToGroup(conversationId, groupId);
|
|
498
498
|
}
|
|
499
|
+
const DEFAULT_GROUP_NAME = "Nova pasta";
|
|
500
|
+
const isCreatingGroup = ref(false);
|
|
501
|
+
function nextGroupName() {
|
|
502
|
+
const names = new Set(groups.value.map((group) => group.name));
|
|
503
|
+
if (!names.has(DEFAULT_GROUP_NAME))
|
|
504
|
+
return DEFAULT_GROUP_NAME;
|
|
505
|
+
let index = 2;
|
|
506
|
+
while (names.has(`${DEFAULT_GROUP_NAME} ${index}`))
|
|
507
|
+
index += 1;
|
|
508
|
+
return `${DEFAULT_GROUP_NAME} ${index}`;
|
|
509
|
+
}
|
|
510
|
+
async function createNewGroup() {
|
|
511
|
+
if (isCreatingGroup.value)
|
|
512
|
+
return;
|
|
513
|
+
isCreatingGroup.value = true;
|
|
514
|
+
const group = await createGroup(nextGroupName());
|
|
515
|
+
isCreatingGroup.value = false;
|
|
516
|
+
if (group)
|
|
517
|
+
pendingRenameGroupId.value = group.id;
|
|
518
|
+
}
|
|
519
|
+
function startUngroupedConversation() {
|
|
520
|
+
if (options.startConversation) {
|
|
521
|
+
void options.startConversation(null);
|
|
522
|
+
} else if (options.resetConversation) {
|
|
523
|
+
void options.resetConversation();
|
|
524
|
+
}
|
|
525
|
+
}
|
|
499
526
|
function startConversationInGroup(groupId) {
|
|
500
527
|
setGroupOpen(groupId, true);
|
|
501
528
|
if (options.startConversation) {
|
|
@@ -562,6 +589,8 @@ export function useConversationList(options) {
|
|
|
562
589
|
isDropTarget,
|
|
563
590
|
getConversationItemProps,
|
|
564
591
|
handleConversationDrop,
|
|
565
|
-
startConversationInGroup
|
|
592
|
+
startConversationInGroup,
|
|
593
|
+
startUngroupedConversation,
|
|
594
|
+
createNewGroup
|
|
566
595
|
};
|
|
567
596
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getChatApiErrorMessage } from "../../shared/chat-api-error.js";
|
|
1
2
|
import { useChatAuth } from "#chat-auth";
|
|
2
3
|
import * as Sentry from "@sentry/nuxt";
|
|
3
4
|
import { resolveChatStateScope } from "../scope.js";
|
|
@@ -348,7 +349,7 @@ export function useConversations() {
|
|
|
348
349
|
} catch (err) {
|
|
349
350
|
removeConversationFromLoadedBuckets(optimisticConversation.id, requestRuntimeScope);
|
|
350
351
|
restoreConversationMetadata(requestRuntimeScope, metadataSnapshot);
|
|
351
|
-
const message = err
|
|
352
|
+
const message = getChatApiErrorMessage(err) ?? "Erro ao criar conversa";
|
|
352
353
|
error.value = message;
|
|
353
354
|
statusToast.update({
|
|
354
355
|
text: "Erro ao criar conversa",
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { useChatAuth } from '#chat-auth';
|
|
1
2
|
import type { ConversationEvent } from '../../types/schemas/chat/conversations.js';
|
|
2
3
|
import type { ChatFeatureConfig } from '../feature-config.js';
|
|
3
4
|
import type { ChatActor, ChatSidebarConfig, ChatSuggestion } from '../types.js';
|
|
4
5
|
type EmbedUser = ChatActor;
|
|
5
6
|
type __VLS_Props = {
|
|
7
|
+
syncBrowserState?: boolean;
|
|
6
8
|
conversationId?: string | null;
|
|
7
9
|
conversationEvents?: readonly ConversationEvent[] | null;
|
|
8
10
|
composerDisabled?: boolean;
|
|
@@ -15,13 +17,21 @@ type __VLS_Props = {
|
|
|
15
17
|
user?: EmbedUser | null;
|
|
16
18
|
features?: Partial<ChatFeatureConfig>;
|
|
17
19
|
};
|
|
18
|
-
declare var __VLS_11: {}, __VLS_96:
|
|
20
|
+
declare var __VLS_11: {}, __VLS_96: {
|
|
21
|
+
message: useChatAuth;
|
|
22
|
+
}, __VLS_127: {}, __VLS_129: {}, __VLS_210: {
|
|
23
|
+
message: useChatAuth;
|
|
24
|
+
};
|
|
19
25
|
type __VLS_Slots = {} & {
|
|
20
26
|
'sidebar-bottom'?: (props: typeof __VLS_11) => any;
|
|
21
27
|
} & {
|
|
22
28
|
'failed-message-actions'?: (props: typeof __VLS_96) => any;
|
|
23
29
|
} & {
|
|
24
|
-
'
|
|
30
|
+
'topbar-leading'?: (props: typeof __VLS_127) => any;
|
|
31
|
+
} & {
|
|
32
|
+
'topbar-leading'?: (props: typeof __VLS_129) => any;
|
|
33
|
+
} & {
|
|
34
|
+
'failed-message-actions'?: (props: typeof __VLS_210) => any;
|
|
25
35
|
};
|
|
26
36
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
27
37
|
"update:conversationId": (value: string | null) => any;
|
|
@@ -35,6 +45,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
35
45
|
compact: boolean;
|
|
36
46
|
hideSettings: boolean;
|
|
37
47
|
hideSidebar: boolean;
|
|
48
|
+
syncBrowserState: boolean;
|
|
38
49
|
initialConversationId: string | null;
|
|
39
50
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
40
51
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|