@meistrari/chat-nuxt 1.1.2 → 1.2.0

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.
Files changed (151) hide show
  1. package/README.md +95 -11
  2. package/dist/module.d.mts +5 -0
  3. package/dist/module.json +2 -2
  4. package/dist/module.mjs +96 -23
  5. package/dist/runtime/components/chat/conversation-list.d.vue.ts +1 -0
  6. package/dist/runtime/components/chat/conversation-list.vue +22 -2
  7. package/dist/runtime/components/chat/conversation-list.vue.d.ts +1 -0
  8. package/dist/runtime/components/chat/message-list.d.vue.ts +1 -0
  9. package/dist/runtime/components/chat/message-list.vue +23 -2
  10. package/dist/runtime/components/chat/message-list.vue.d.ts +1 -0
  11. package/dist/runtime/composables/useChat.d.ts +2 -1
  12. package/dist/runtime/composables/useChat.js +32 -3
  13. package/dist/runtime/composables/useChatApi.js +2 -1
  14. package/dist/runtime/composables/useConversations.d.ts +3 -2
  15. package/dist/runtime/composables/useConversations.js +99 -11
  16. package/dist/runtime/composables/useEmbedConfig.d.ts +11 -6
  17. package/dist/runtime/composables/useEmbedConfig.js +35 -7
  18. package/dist/runtime/composables/useIDB.js +4 -0
  19. package/dist/runtime/composables/usePdf.d.ts +840 -1
  20. package/dist/runtime/composables/usePdf.js +21 -3
  21. package/dist/runtime/composables/useWorkspaceContextFiles.d.ts +3 -3
  22. package/dist/runtime/composables/useWorkspaceContextFiles.js +19 -10
  23. package/dist/runtime/composables/useWorkspaceCredentials.d.ts +3 -3
  24. package/dist/runtime/composables/useWorkspaceExternalSkills.d.ts +1 -1
  25. package/dist/runtime/composables/useWorkspaceExternalSkills.js +5 -6
  26. package/dist/runtime/composables/useWorkspacePersonalization.d.ts +1 -1
  27. package/dist/runtime/composables/useWorkspacePersonalization.js +4 -5
  28. package/dist/runtime/composables/useWorkspaceSettings.js +12 -9
  29. package/dist/runtime/embed/components/ChatConfigurationModal.d.vue.ts +25 -0
  30. package/dist/runtime/embed/components/ChatConfigurationModal.vue +373 -0
  31. package/dist/runtime/embed/components/ChatConfigurationModal.vue.d.ts +25 -0
  32. package/dist/runtime/embed/components/ChatEmbed.vue +12 -1
  33. package/dist/runtime/embed/components/ChatEmbedInner.vue +31 -16
  34. package/dist/runtime/embed/components/configuration/ChatConfigurationContextFilesTab.d.vue.ts +22 -0
  35. package/dist/runtime/embed/components/configuration/ChatConfigurationContextFilesTab.vue +133 -0
  36. package/dist/runtime/embed/components/configuration/ChatConfigurationContextFilesTab.vue.d.ts +22 -0
  37. package/dist/runtime/embed/components/configuration/ChatConfigurationCredentialsTab.d.vue.ts +10 -0
  38. package/dist/runtime/embed/components/configuration/ChatConfigurationCredentialsTab.vue +220 -0
  39. package/dist/runtime/embed/components/configuration/ChatConfigurationCredentialsTab.vue.d.ts +10 -0
  40. package/dist/runtime/embed/components/configuration/ChatConfigurationExternalSkillsTab.d.vue.ts +32 -0
  41. package/dist/runtime/embed/components/configuration/ChatConfigurationExternalSkillsTab.vue +222 -0
  42. package/dist/runtime/embed/components/configuration/ChatConfigurationExternalSkillsTab.vue.d.ts +32 -0
  43. package/dist/runtime/embed/components/configuration/ChatConfigurationKnowledgeSourcesTab.d.vue.ts +18 -0
  44. package/dist/runtime/embed/components/configuration/ChatConfigurationKnowledgeSourcesTab.vue +142 -0
  45. package/dist/runtime/embed/components/configuration/ChatConfigurationKnowledgeSourcesTab.vue.d.ts +18 -0
  46. package/dist/runtime/embed/components/configuration/ChatConfigurationPersonalizationTab.d.vue.ts +10 -0
  47. package/dist/runtime/embed/components/configuration/ChatConfigurationPersonalizationTab.vue +37 -0
  48. package/dist/runtime/embed/components/configuration/ChatConfigurationPersonalizationTab.vue.d.ts +10 -0
  49. package/dist/runtime/embed/components/configuration/ChatConfigurationTelaToolsTab.d.vue.ts +20 -0
  50. package/dist/runtime/embed/components/configuration/ChatConfigurationTelaToolsTab.vue +146 -0
  51. package/dist/runtime/embed/components/configuration/ChatConfigurationTelaToolsTab.vue.d.ts +20 -0
  52. package/dist/runtime/server/api/admin/trigger-usage-report.post.d.ts +4 -1
  53. package/dist/runtime/server/api/admin/trigger-usage-report.post.js +2 -0
  54. package/dist/runtime/server/api/chat/workspace/settings.get.d.ts +1 -1
  55. package/dist/runtime/server/api/chat/workspace/settings.get.js +1 -0
  56. package/dist/runtime/server/api/conversations/[id]/cancel.post.d.ts +4 -1
  57. package/dist/runtime/server/api/conversations/[id]/cancel.post.js +1 -0
  58. package/dist/runtime/server/api/conversations/[id]/clear.post.d.ts +1 -1
  59. package/dist/runtime/server/api/conversations/[id]/clear.post.js +1 -0
  60. package/dist/runtime/server/api/conversations/[id]/duplicate.post.d.ts +1 -1
  61. package/dist/runtime/server/api/conversations/[id]/duplicate.post.js +46 -12
  62. package/dist/runtime/server/api/conversations/[id]/files.get.d.ts +1 -1
  63. package/dist/runtime/server/api/conversations/[id]/files.get.js +2 -0
  64. package/dist/runtime/server/api/conversations/[id]/index.delete.d.ts +3 -1
  65. package/dist/runtime/server/api/conversations/[id]/index.delete.js +1 -0
  66. package/dist/runtime/server/api/conversations/[id]/index.get.d.ts +1 -1
  67. package/dist/runtime/server/api/conversations/[id]/index.get.js +1 -0
  68. package/dist/runtime/server/api/conversations/[id]/index.patch.d.ts +1 -1
  69. package/dist/runtime/server/api/conversations/[id]/index.patch.js +1 -0
  70. package/dist/runtime/server/api/conversations/[id]/messages/[messageId]/retry.post.d.ts +1 -1
  71. package/dist/runtime/server/api/conversations/[id]/messages/[messageId]/retry.post.js +2 -0
  72. package/dist/runtime/server/api/conversations/[id]/messages/index.get.d.ts +14 -1
  73. package/dist/runtime/server/api/conversations/[id]/messages/index.get.js +2 -0
  74. package/dist/runtime/server/api/conversations/[id]/messages/index.post.d.ts +4 -1
  75. package/dist/runtime/server/api/conversations/[id]/messages/index.post.js +2 -0
  76. package/dist/runtime/server/api/conversations/[id]/usage.get.d.ts +1 -1
  77. package/dist/runtime/server/api/conversations/[id]/usage.get.js +1 -0
  78. package/dist/runtime/server/api/conversations/generate-title.post.d.ts +3 -1
  79. package/dist/runtime/server/api/conversations/generate-title.post.js +2 -0
  80. package/dist/runtime/server/api/conversations/index.get.d.ts +1 -1
  81. package/dist/runtime/server/api/conversations/index.get.js +1 -0
  82. package/dist/runtime/server/api/conversations/index.post.d.ts +1 -1
  83. package/dist/runtime/server/api/conversations/index.post.js +1 -0
  84. package/dist/runtime/server/api/external-skills/discover.post.d.ts +1 -1
  85. package/dist/runtime/server/api/external-skills/discover.post.js +2 -0
  86. package/dist/runtime/server/api/github/disconnect.post.d.ts +3 -1
  87. package/dist/runtime/server/api/github/disconnect.post.js +2 -0
  88. package/dist/runtime/server/api/github/status.get.d.ts +1 -1
  89. package/dist/runtime/server/api/github/status.get.js +2 -0
  90. package/dist/runtime/server/api/tela/canvas.get.d.ts +1 -1
  91. package/dist/runtime/server/api/tela/canvas.get.js +1 -0
  92. package/dist/runtime/server/api/tela/projects.get.d.ts +1 -1
  93. package/dist/runtime/server/api/tela/projects.get.js +1 -0
  94. package/dist/runtime/server/api/tela/workspaces.get.d.ts +1 -1
  95. package/dist/runtime/server/api/tela/workspaces.get.js +1 -0
  96. package/dist/runtime/server/api/tela/workstations.get.d.ts +1 -1
  97. package/dist/runtime/server/api/tela/workstations.get.js +1 -0
  98. package/dist/runtime/server/api/vault/permalink-metadata.post.d.ts +5 -1
  99. package/dist/runtime/server/api/vault/permalink-metadata.post.js +2 -0
  100. package/dist/runtime/server/api/vault/resolve.post.d.ts +9 -1
  101. package/dist/runtime/server/api/vault/resolve.post.js +2 -0
  102. package/dist/runtime/server/api/vault/upload.post.d.ts +6 -1
  103. package/dist/runtime/server/api/vault/upload.post.js +2 -0
  104. package/dist/runtime/server/api/workspace/credentials/[id].delete.d.ts +3 -1
  105. package/dist/runtime/server/api/workspace/credentials/[id].delete.js +1 -0
  106. package/dist/runtime/server/api/workspace/credentials/[id].put.d.ts +1 -1
  107. package/dist/runtime/server/api/workspace/credentials/[id].put.js +1 -0
  108. package/dist/runtime/server/api/workspace/credentials/index.get.d.ts +1 -1
  109. package/dist/runtime/server/api/workspace/credentials/index.get.js +1 -0
  110. package/dist/runtime/server/api/workspace/credentials/index.post.d.ts +1 -1
  111. package/dist/runtime/server/api/workspace/credentials/index.post.js +1 -0
  112. package/dist/runtime/server/api/workspace/settings.get.d.ts +1 -1
  113. package/dist/runtime/server/api/workspace/settings.get.js +1 -0
  114. package/dist/runtime/server/api/workspace/settings.patch.d.ts +1 -1
  115. package/dist/runtime/server/api/workspace/settings.patch.js +1 -0
  116. package/dist/runtime/server/api/workspace/usage.get.d.ts +1 -1
  117. package/dist/runtime/server/api/workspace/usage.get.js +1 -0
  118. package/dist/runtime/server/db/index.js +1 -0
  119. package/dist/runtime/server/middleware/domain-validation.d.ts +1 -1
  120. package/dist/runtime/server/middleware/domain-validation.js +2 -0
  121. package/dist/runtime/server/middleware/request-logger.d.ts +1 -1
  122. package/dist/runtime/server/middleware/request-logger.js +1 -0
  123. package/dist/runtime/server/tasks/send-daily-usage-report.d.ts +1 -1
  124. package/dist/runtime/server/tasks/send-daily-usage-report.js +1 -0
  125. package/dist/runtime/server/utils/agent-api.d.ts +1 -1
  126. package/dist/runtime/server/utils/agent-api.js +2 -0
  127. package/dist/runtime/server/utils/auth-api.js +2 -0
  128. package/dist/runtime/server/utils/auth.d.ts +1 -1
  129. package/dist/runtime/server/utils/auth.js +1 -0
  130. package/dist/runtime/server/utils/tela-api.d.ts +1 -1
  131. package/dist/runtime/server/utils/tela-api.js +2 -0
  132. package/dist/runtime/server/utils/workspace.js +1 -0
  133. package/dist/runtime/types/chat.d.ts +2 -1
  134. package/dist/runtime/types/workspace-settings.d.ts +3 -0
  135. package/dist/runtime/types/workspace-settings.js +0 -0
  136. package/dist/runtime/utils/conversation-list-skeleton.d.ts +31 -0
  137. package/dist/runtime/utils/conversation-list-skeleton.js +12 -0
  138. package/dist/runtime/utils/file.js +42 -42
  139. package/dist/types.d.mts +2 -0
  140. package/package.json +24 -12
  141. package/dist/runtime/composables/PageNavigation.d.ts +0 -13
  142. package/dist/runtime/composables/PageNavigation.js +0 -18
  143. /package/dist/runtime/components/{TelaChat.d.vue.ts → MeistrariChatEmbed.d.vue.ts} +0 -0
  144. /package/dist/runtime/components/{TelaChat.vue → MeistrariChatEmbed.vue} +0 -0
  145. /package/dist/runtime/components/{TelaChat.vue.d.ts → MeistrariChatEmbed.vue.d.ts} +0 -0
  146. /package/dist/runtime/components/{pdf-preview.d.vue.ts → pdf-preview.client.d.vue.ts} +0 -0
  147. /package/dist/runtime/components/{pdf-preview.vue → pdf-preview.client.vue} +0 -0
  148. /package/dist/runtime/components/{pdf-preview.vue.d.ts → pdf-preview.client.vue.d.ts} +0 -0
  149. /package/dist/runtime/components/{pdf-viewer.d.vue.ts → pdf-viewer.client.d.vue.ts} +0 -0
  150. /package/dist/runtime/components/{pdf-viewer.vue → pdf-viewer.client.vue} +0 -0
  151. /package/dist/runtime/components/{pdf-viewer.vue.d.ts → pdf-viewer.client.vue.d.ts} +0 -0
@@ -0,0 +1,373 @@
1
+ <script setup>
2
+ import { useMagicKeys } from "@vueuse/core";
3
+ const props = defineProps({
4
+ open: { type: Boolean, required: true },
5
+ settings: { type: null, required: false },
6
+ initialTab: { type: String, required: false, default: "personalization" },
7
+ saving: { type: Boolean, required: false, default: false }
8
+ });
9
+ const emit = defineEmits(["update:open", "save"]);
10
+ const { uploadFiles, uploading } = useFileUpload();
11
+ const { canvas, projects, workstations, loadingWorkstations } = useTela();
12
+ const { setKnowledgeSources } = useKnowledgeSources();
13
+ const statusToast = useStatusToast();
14
+ const { escape } = useMagicKeys();
15
+ const {
16
+ settings: workspaceSettings,
17
+ loading: workspaceSettingsLoading,
18
+ fetchSettings,
19
+ updateSettings
20
+ } = useWorkspaceSettings();
21
+ const searchQuery = ref("");
22
+ const activeTab = ref(props.initialTab);
23
+ const showDiscardConfirm = ref(false);
24
+ const loadingInitialSettings = ref(false);
25
+ const hasSettingsOverride = computed(() => props.settings !== void 0);
26
+ const mutableSettings = computed(() => hasSettingsOverride.value ? props.settings : workspaceSettings.value);
27
+ const currentSystemMessage = computed(() => mutableSettings.value?.systemMessage ?? null);
28
+ const currentContextFiles = computed(() => mutableSettings.value?.contextFiles ?? null);
29
+ const currentCanvasTools = computed(() => mutableSettings.value?.canvasTools ?? null);
30
+ const currentKnowledgeSources = computed(() => mutableSettings.value?.knowledgeSources ?? null);
31
+ const currentExternalSkills = computed(() => mutableSettings.value?.externalSkills ?? null);
32
+ const personalization = useWorkspacePersonalization(currentSystemMessage);
33
+ const telaTools = useWorkspaceTelaTools(canvas, projects, searchQuery, currentCanvasTools);
34
+ const knowledgeSources = useWorkspaceKnowledgeSources(workstations, canvas, projects, searchQuery, currentKnowledgeSources);
35
+ const contextFiles = useWorkspaceContextFiles(searchQuery, currentContextFiles);
36
+ const externalSkills = useWorkspaceExternalSkills(currentExternalSkills, searchQuery);
37
+ const settingsTabs = [
38
+ { value: "personalization", label: "Personaliza\xE7\xE3o", icon: "i-ph-sliders" },
39
+ { value: "context-files", label: "Arquivos de contexto", icon: "i-ph-file-text" },
40
+ { value: "knowledge-sources", label: "Tela workstations", icon: "i-ph-database" },
41
+ { value: "tela-tools", label: "Skills Tela", icon: "i-ph-puzzle-piece" },
42
+ { value: "external-skills", label: "Skills Externas", icon: "i-ph-wrench" },
43
+ { value: "credentials", label: "Credenciais", icon: "i-ph-password-bold" }
44
+ ];
45
+ const hasChanges = computed(
46
+ () => personalization.hasChanges.value || contextFiles.hasChanges.value || telaTools.hasChanges.value || knowledgeSources.hasChanges.value || externalSkills.hasChanges.value
47
+ );
48
+ const isBusy = computed(() => props.saving || uploading.value || !hasSettingsOverride.value && workspaceSettingsLoading.value);
49
+ const gitHubButtonText = computed(() => externalSkills.getGitHubButtonText());
50
+ watch(() => escape?.value, (pressed) => {
51
+ if (pressed && props.open && !showDiscardConfirm.value)
52
+ handleClose();
53
+ });
54
+ watch(() => props.open, (isOpen) => {
55
+ if (isOpen) {
56
+ searchQuery.value = "";
57
+ activateTab(props.initialTab);
58
+ if (!hasSettingsOverride.value && !mutableSettings.value) {
59
+ void loadSettings();
60
+ return;
61
+ }
62
+ initializeConfigurationState();
63
+ } else {
64
+ loadingInitialSettings.value = false;
65
+ }
66
+ });
67
+ watch(() => props.initialTab, (tab) => {
68
+ if (props.open)
69
+ activateTab(tab);
70
+ });
71
+ watch(currentSystemMessage, () => {
72
+ if (props.open)
73
+ personalization.initialize();
74
+ });
75
+ watch(mutableSettings, (settings, previousSettings) => {
76
+ if (props.open && hasSettingsOverride.value && settings && !previousSettings)
77
+ initializeConfigurationState();
78
+ });
79
+ function initializeConfigurationState() {
80
+ personalization.initialize();
81
+ telaTools.initialize();
82
+ knowledgeSources.initialize();
83
+ contextFiles.initialize();
84
+ externalSkills.initialize();
85
+ }
86
+ function activateTab(tab) {
87
+ activeTab.value = tab;
88
+ searchQuery.value = "";
89
+ if (tab === "external-skills")
90
+ void externalSkills.fetchGitHubConnection();
91
+ }
92
+ async function loadSettings() {
93
+ loadingInitialSettings.value = true;
94
+ try {
95
+ await fetchSettings();
96
+ initializeConfigurationState();
97
+ } catch (error) {
98
+ console.error("Failed to load workspace settings:", error);
99
+ statusToast.update({
100
+ text: "Erro ao carregar configura\xE7\xF5es",
101
+ icon: "i-ph-warning"
102
+ });
103
+ } finally {
104
+ loadingInitialSettings.value = false;
105
+ }
106
+ }
107
+ async function handleSave() {
108
+ if (!hasChanges.value || isBusy.value)
109
+ return;
110
+ try {
111
+ const updates = {};
112
+ if (personalization.hasChanges.value)
113
+ updates.systemMessage = personalization.getSystemMessage();
114
+ if (contextFiles.hasChanges.value) {
115
+ const pendingFilesList = contextFiles.getPendingFiles();
116
+ const uploadedFiles = pendingFilesList.length > 0 ? await uploadFiles(pendingFilesList) : [];
117
+ const newContextFiles = [
118
+ ...contextFiles.getKeptContextFiles(),
119
+ ...uploadedFiles.map((f) => ({ url: f.url, name: f.name, mimeType: f.mimeType }))
120
+ ];
121
+ updates.contextFiles = newContextFiles.length > 0 ? newContextFiles : null;
122
+ }
123
+ if (telaTools.hasChanges.value) {
124
+ const tools = telaTools.buildCanvasTools();
125
+ updates.canvasTools = tools.length > 0 ? tools : null;
126
+ }
127
+ let pendingKnowledgeSources = null;
128
+ if (knowledgeSources.hasChanges.value) {
129
+ const sources = knowledgeSources.buildKnowledgeSources();
130
+ updates.knowledgeSources = sources.length > 0 ? sources : null;
131
+ pendingKnowledgeSources = sources.length > 0 ? sources : null;
132
+ }
133
+ if (externalSkills.hasChanges.value)
134
+ updates.externalSkills = externalSkills.buildExternalSkills();
135
+ const shouldUpdateKnowledgeSources = pendingKnowledgeSources !== null || knowledgeSources.hasChanges.value;
136
+ const shouldClearContextFiles = contextFiles.hasChanges.value;
137
+ const shouldResetExternalSkills = externalSkills.hasChanges.value;
138
+ const onSaved = () => {
139
+ if (shouldUpdateKnowledgeSources)
140
+ setKnowledgeSources(pendingKnowledgeSources);
141
+ if (shouldClearContextFiles)
142
+ contextFiles.clearPendingFiles();
143
+ if (shouldResetExternalSkills)
144
+ externalSkills.initialize();
145
+ };
146
+ if (hasSettingsOverride.value) {
147
+ emit("save", { updates, onSaved });
148
+ return;
149
+ }
150
+ await updateSettings(updates);
151
+ onSaved();
152
+ statusToast.update({
153
+ text: "Configura\xE7\xF5es salvas",
154
+ icon: "i-ph-check"
155
+ });
156
+ emit("update:open", false);
157
+ } catch (error) {
158
+ console.error("Failed to prepare settings update:", error);
159
+ statusToast.update({
160
+ text: "Erro ao salvar configura\xE7\xF5es",
161
+ icon: "i-ph-warning"
162
+ });
163
+ }
164
+ }
165
+ function handleClose() {
166
+ if (isBusy.value)
167
+ return;
168
+ if (hasChanges.value)
169
+ showDiscardConfirm.value = true;
170
+ else
171
+ emit("update:open", false);
172
+ }
173
+ function confirmDiscard() {
174
+ showDiscardConfirm.value = false;
175
+ emit("update:open", false);
176
+ }
177
+ function cancelDiscard() {
178
+ showDiscardConfirm.value = false;
179
+ }
180
+ </script>
181
+
182
+ <template>
183
+ <TelaModal
184
+ :model-value="open"
185
+ modal-width="lg"
186
+ compact
187
+ hide-dividers
188
+ hide-header
189
+ class="!w-[min(1024px,95vw)] !max-w-[min(1024px,95vw)] p-0!"
190
+ @update:model-value="handleClose"
191
+ >
192
+ <div flex class="h-[min(722px,90vh)]" w-full>
193
+ <div w-256px bg-neutral-100 flex="~ col" overflow-hidden rounded-l-16px relative>
194
+ <p text-12px text-secondary px-16px pt-16px leading-16px style="color: #767E88;">
195
+ Configurações do Workspace
196
+ </p>
197
+
198
+ <div flex="~ col" gap-1px px-6px mt-24px>
199
+ <button
200
+ v-for="tab in settingsTabs"
201
+ :key="tab.value"
202
+ flex items-center gap-12px
203
+ px-12px py-7px
204
+ rounded-8px
205
+ cursor-pointer
206
+ transition
207
+ text-left
208
+ w-full
209
+ :class="[
210
+ activeTab === tab.value ? 'bg-black/4' : 'hover:bg-black/2'
211
+ ]"
212
+ @click="activateTab(tab.value)"
213
+ >
214
+ <div
215
+ :class="tab.icon"
216
+ text-16px
217
+ :style="{ color: '#6B7280' }"
218
+ />
219
+ <span
220
+ text-14px
221
+ tracking="-.15px"
222
+ leading-18px
223
+ font-460
224
+ :class="[
225
+ activeTab === tab.value ? 'text-primary' : 'text-secondary'
226
+ ]"
227
+ >
228
+ {{ tab.label }}
229
+ </span>
230
+ </button>
231
+ </div>
232
+
233
+ <div flex-1 />
234
+
235
+ <div absolute bottom-0 left-0 w-full h-56px bg-gradient-to-t from-neutral-50 to-transparent pointer-events-none />
236
+ <div px-16px pb-16px relative z-10>
237
+ <button
238
+ p-6px rounded-full
239
+ bg-white b=".5px gray-200"
240
+ flex items-center justify-center
241
+ cursor-pointer
242
+ hover:bg-gray-50
243
+ transition
244
+ >
245
+ <div i-ph-question text-20px style="color: #767E88;" />
246
+ </button>
247
+ </div>
248
+ </div>
249
+
250
+ <div flex-1 flex="~ col" bg-white relative overflow-hidden rounded-r-16px>
251
+ <button
252
+ absolute top-12px right-12px
253
+ p-8px rounded-12px
254
+ hover:bg-gray-100
255
+ transition cursor-pointer
256
+ z-10
257
+ @click="handleClose"
258
+ >
259
+ <div i-ph-x text-24px text-primary />
260
+ </button>
261
+
262
+ <div flex-1 overflow-auto px-48px pt-32px pb-24px>
263
+ <div
264
+ v-if="loadingInitialSettings"
265
+ h-full min-h-360px flex="~ col" items-center justify-center gap-12px
266
+ >
267
+ <div i-ph-spinner animate-spin text-24px text-gray-500 />
268
+ <p text-14px text-gray-500>
269
+ Carregando configurações...
270
+ </p>
271
+ </div>
272
+
273
+ <ChatConfigurationPersonalizationTab
274
+ v-else-if="activeTab === 'personalization'"
275
+ v-model:system-message="personalization.localSystemMessage.value"
276
+ />
277
+
278
+ <ChatConfigurationContextFilesTab
279
+ v-else-if="activeTab === 'context-files'"
280
+ :search-query="searchQuery"
281
+ :filtered-context-files="contextFiles.filteredContextFiles.value"
282
+ :filtered-pending-files="contextFiles.filteredPendingFiles.value"
283
+ :current-file-count="contextFiles.currentFileCount.value"
284
+ :max-files="contextFiles.maxFiles"
285
+ :get-file-type="contextFiles.getFileType"
286
+ @update:search-query="searchQuery = $event"
287
+ @handle-file-select="contextFiles.handleFileSelect"
288
+ @remove-pending-file="contextFiles.removePendingFile"
289
+ @remove-context-file="contextFiles.removeContextFile"
290
+ />
291
+
292
+ <ChatConfigurationKnowledgeSourcesTab
293
+ v-else-if="activeTab === 'knowledge-sources'"
294
+ :search-query="searchQuery"
295
+ :workstations="workstations"
296
+ :loading-workstations="loadingWorkstations"
297
+ :filtered-workstations="knowledgeSources.filteredWorkstations.value"
298
+ :selected-ids="knowledgeSources.selectedKnowledgeSourceIds.value"
299
+ :get-project-name-for-workstation="knowledgeSources.getProjectNameForWorkstation"
300
+ @update:search-query="searchQuery = $event"
301
+ @toggle="knowledgeSources.toggleKnowledgeSource"
302
+ />
303
+
304
+ <ChatConfigurationTelaToolsTab
305
+ v-else-if="activeTab === 'tela-tools'"
306
+ :search-query="searchQuery"
307
+ :canvas="canvas"
308
+ :filtered-canvas-tools="telaTools.filteredCanvasTools.value"
309
+ :selected-tool-ids="telaTools.selectedToolIds.value"
310
+ :all-tools-selected="telaTools.allToolsSelected.value"
311
+ :get-project-name="telaTools.getProjectName"
312
+ @update:search-query="searchQuery = $event"
313
+ @toggle-tool="telaTools.toggleCanvasTool"
314
+ @toggle-all="telaTools.toggleAllTools"
315
+ />
316
+
317
+ <ChatConfigurationExternalSkillsTab
318
+ v-else-if="activeTab === 'external-skills'"
319
+ :search-query="searchQuery"
320
+ :displayed-skills="externalSkills.displayedSkills.value"
321
+ :filtered-skills="externalSkills.filteredSkills.value"
322
+ :has-changes="externalSkills.hasChanges.value"
323
+ :is-pending="externalSkills.isPending"
324
+ :skill-modal-open="externalSkills.skillModalOpen.value"
325
+ :skill-ref-input="externalSkills.skillRefInput.value"
326
+ :skill-error="externalSkills.skillError.value"
327
+ :discovering-skills="externalSkills.discoveringSkills.value"
328
+ :git-hub-button-text="gitHubButtonText"
329
+ @update:search-query="searchQuery = $event"
330
+ @update:skill-modal-open="externalSkills.skillModalOpen.value = $event"
331
+ @update:skill-ref-input="externalSkills.skillRefInput.value = $event"
332
+ @remove-skill="externalSkills.removeSkill"
333
+ @close-skill-modal="externalSkills.closeSkillModal"
334
+ @handle-add-skill-and-close="externalSkills.handleAddSkillAndClose"
335
+ @connect-git-hub="externalSkills.connectGitHub"
336
+ />
337
+
338
+ <ChatConfigurationCredentialsTab
339
+ v-else-if="activeTab === 'credentials'"
340
+ :search-query="searchQuery"
341
+ @update:search-query="searchQuery = $event"
342
+ />
343
+ </div>
344
+
345
+ <div flex-shrink-0 px-48px pb-48px flex justify-end gap-12px>
346
+ <TelaButton
347
+ size="lg"
348
+ :disabled="!hasChanges || isBusy"
349
+ @click="handleSave"
350
+ >
351
+ <span v-if="isBusy" flex items-center gap-6px>
352
+ <div i-ph-spinner animate-spin />
353
+ Salvando...
354
+ </span>
355
+ <span v-else>Salvar</span>
356
+ </TelaButton>
357
+ </div>
358
+ </div>
359
+ </div>
360
+
361
+ <TelaConfirmationModal
362
+ v-model:open="showDiscardConfirm"
363
+ title="Descartar alterações?"
364
+ variant="danger"
365
+ confirm-button-text="Descartar"
366
+ cancel-button-text="Continuar editando"
367
+ @confirm="confirmDiscard"
368
+ @cancel="cancelDiscard"
369
+ >
370
+ Você tem alterações não salvas. Deseja descartá-las?
371
+ </TelaConfirmationModal>
372
+ </TelaModal>
373
+ </template>
@@ -0,0 +1,25 @@
1
+ import type { DeepReadonly } from 'vue';
2
+ import type { WorkspaceSettings, WorkspaceSettingsUpdate } from '../../composables/useWorkspaceSettings.js';
3
+ export type ChatConfigurationTab = 'personalization' | 'context-files' | 'knowledge-sources' | 'tela-tools' | 'external-skills' | 'credentials';
4
+ export type ChatConfigurationSavePayload = {
5
+ updates: WorkspaceSettingsUpdate;
6
+ onSaved: () => void;
7
+ };
8
+ type __VLS_Props = {
9
+ open: boolean;
10
+ settings?: DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null;
11
+ initialTab?: ChatConfigurationTab;
12
+ saving?: boolean;
13
+ };
14
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
15
+ save: (payload: ChatConfigurationSavePayload) => any;
16
+ "update:open": (value: boolean) => any;
17
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
18
+ onSave?: ((payload: ChatConfigurationSavePayload) => any) | undefined;
19
+ "onUpdate:open"?: ((value: boolean) => any) | undefined;
20
+ }>, {
21
+ initialTab: ChatConfigurationTab;
22
+ saving: boolean;
23
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
+ declare const _default: typeof __VLS_export;
25
+ export default _default;
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { provideEmbedConfig, useEmbedConfig } from "../../composables/useEmbedConfig";
2
3
  import ChatEmbedInner from "./ChatEmbedInner.vue";
3
4
  const props = defineProps({
4
5
  workspaceId: { type: String, required: true },
@@ -10,7 +11,17 @@ const props = defineProps({
10
11
  features: { type: Object, required: false }
11
12
  });
12
13
  defineEmits(["update:conversationId"]);
13
- provideEmbedConfig(props);
14
+ const parentEmbedConfig = useEmbedConfig();
15
+ if (import.meta.dev && parentEmbedConfig) {
16
+ watchEffect(() => {
17
+ const parentWorkspaceId = parentEmbedConfig.workspaceId.value.trim();
18
+ const propWorkspaceId = props.workspaceId.trim();
19
+ if (parentWorkspaceId && propWorkspaceId && parentWorkspaceId !== propWorkspaceId) {
20
+ console.warn(`[MeistrariChatEmbed] workspaceId prop (${propWorkspaceId}) differs from parent embed config (${parentWorkspaceId}); using prop value for this embed.`);
21
+ }
22
+ });
23
+ }
24
+ provideEmbedConfig(props, { syncGlobal: !parentEmbedConfig });
14
25
  </script>
15
26
 
16
27
  <template>
@@ -1,5 +1,6 @@
1
1
  <script setup>
2
2
  import { exportConversationToMarkdown } from "../../utils/export-conversation";
3
+ import { conversationListSkeletonRows } from "../../utils/conversation-list-skeleton";
3
4
  import {
4
5
  normalizeConversationId,
5
6
  resolveChatFeatures,
@@ -18,9 +19,9 @@ const embedConfig = useEmbedConfig();
18
19
  const { user: authUser } = useTelaApplicationAuth();
19
20
  const { getMember } = useWorkspaceMembers();
20
21
  const statusToast = useStatusToast();
21
- const { conversations, fetchConversations, createConversation, deleteConversation, renameConversation, duplicateConversation } = useConversations();
22
+ const { conversations, loading: conversationsLoading, fetchConversations, createConversation, deleteConversation, renameConversation, duplicateConversation, updateConversationInList } = useConversations();
22
23
  const { settings: workspaceSettingsState, fetchSettings } = useWorkspaceSettings();
23
- const effectiveWorkspaceSettings = computed(() => embedConfig?.workspaceSettings.value ?? workspaceSettingsState.value);
24
+ const effectiveWorkspaceSettings = computed(() => embedConfig?.workspaceSettings.value !== void 0 ? embedConfig.workspaceSettings.value : workspaceSettingsState.value);
24
25
  const { closePanel: closeFilesPanel } = useConversationFilesPanel();
25
26
  const activeConversationId = ref(
26
27
  normalizeConversationId(props.conversationId) ?? normalizeConversationId(props.initialConversationId)
@@ -45,6 +46,7 @@ const {
45
46
  animatedTitle,
46
47
  hasPendingMessage,
47
48
  loadConversation,
49
+ setConversation,
48
50
  sendMessage,
49
51
  retryMessage,
50
52
  cancelConversation,
@@ -200,7 +202,7 @@ const displayTitle = computed(() => {
200
202
  });
201
203
  watch(
202
204
  () => [currentConversation.value?.id ?? null, currentConversation.value?.title ?? null],
203
- ([conversationId, conversationTitle], [previousConversationId]) => {
205
+ ([conversationId, conversationTitle], [previousConversationId, previousTitle]) => {
204
206
  if (conversationId !== previousConversationId) {
205
207
  optimisticTitle.value = null;
206
208
  return;
@@ -208,6 +210,9 @@ watch(
208
210
  if (optimisticTitle.value !== null && conversationTitle === optimisticTitle.value) {
209
211
  optimisticTitle.value = null;
210
212
  }
213
+ if (conversationTitle && conversationTitle !== previousTitle && currentConversation.value) {
214
+ updateConversationInList(currentConversation.value);
215
+ }
211
216
  }
212
217
  );
213
218
  const currentUser = computed(() => props.user ?? authUser.value ?? null);
@@ -218,22 +223,23 @@ const conversationCreator = computed(
218
223
  })
219
224
  );
220
225
  async function handleSend(content, files, model) {
226
+ let createdConversationId = null;
221
227
  if (!activeConversationId.value || !currentConversation.value) {
222
228
  const conversation = await createConversation({
223
229
  model: model ?? selectedModel.value
224
230
  });
225
231
  if (!conversation)
226
232
  return;
227
- updateConversationId(conversation.id);
228
- await ensureConversationLoaded(conversation.id);
229
- if (!currentConversation.value) {
230
- statusToast.update({ text: "Erro ao carregar conversa", icon: "i-ph-warning" });
231
- return;
232
- }
233
+ setConversation(conversation);
234
+ createdConversationId = conversation.id;
233
235
  }
234
236
  if (!currentConversation.value)
235
237
  return;
236
- await sendMessage(content, files.length > 0 ? files : void 0, model);
238
+ const sendPromise = sendMessage(content, files.length > 0 ? files : void 0, model);
239
+ if (createdConversationId) {
240
+ updateConversationId(createdConversationId);
241
+ }
242
+ await sendPromise;
237
243
  }
238
244
  async function handleRetry(messageId) {
239
245
  await retryMessage(messageId);
@@ -295,8 +301,8 @@ async function handleDuplicate() {
295
301
  return;
296
302
  const duplicated = await duplicateConversation(currentConversation.value.id);
297
303
  if (duplicated) {
304
+ setConversation(duplicated);
298
305
  updateConversationId(duplicated.id);
299
- await ensureConversationLoaded(duplicated.id);
300
306
  }
301
307
  }
302
308
  async function handleExport() {
@@ -322,9 +328,6 @@ async function handleDelete() {
322
328
  await handleNewConversation();
323
329
  }
324
330
  }
325
- onBeforeUnmount(() => {
326
- clearConversation();
327
- });
328
331
  </script>
329
332
 
330
333
  <template>
@@ -351,7 +354,16 @@ onBeforeUnmount(() => {
351
354
  </div>
352
355
 
353
356
  <div flex-1 overflow-y-auto px-4px>
354
- <div v-if="visibleConversations.length === 0" p-16px text-center>
357
+ <div v-if="conversationsLoading && visibleConversations.length === 0" flex="~ col" gap-1px px-8px py-8px>
358
+ <div
359
+ v-for="row in conversationListSkeletonRows"
360
+ :key="row.id"
361
+ flex items-center h-32px px-8px rounded-8px
362
+ >
363
+ <TelaSkeleton rounded-6px bg-neutral-200 :style="{ width: row.width, height: '13px' }" />
364
+ </div>
365
+ </div>
366
+ <div v-else-if="visibleConversations.length === 0" p-16px text-center>
355
367
  <p text-14px text-neutral-400>
356
368
  Nenhuma conversa ainda
357
369
  </p>
@@ -449,7 +461,10 @@ onBeforeUnmount(() => {
449
461
  </template>
450
462
 
451
463
  <template v-else-if="loading">
452
- <div flex-1 pt-64px />
464
+ <ChatMessageList
465
+ :messages="[]"
466
+ loading
467
+ />
453
468
  <ChatMessageInput
454
469
  v-model:model="selectedModel"
455
470
  :disabled="true"
@@ -0,0 +1,22 @@
1
+ import type { ContextFile } from '../../../server/db/schema.js';
2
+ type __VLS_Props = {
3
+ searchQuery: string;
4
+ filteredContextFiles: readonly ContextFile[];
5
+ filteredPendingFiles: readonly File[];
6
+ currentFileCount: number;
7
+ maxFiles: number;
8
+ getFileType: (fileName: string) => string;
9
+ };
10
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
11
+ handleFileSelect: (event: Event) => any;
12
+ removeContextFile: (url: string) => any;
13
+ removePendingFile: (file: File) => any;
14
+ "update:searchQuery": (value: string) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
16
+ onHandleFileSelect?: ((event: Event) => any) | undefined;
17
+ onRemoveContextFile?: ((url: string) => any) | undefined;
18
+ onRemovePendingFile?: ((file: File) => any) | undefined;
19
+ "onUpdate:searchQuery"?: ((value: string) => any) | undefined;
20
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
21
+ declare const _default: typeof __VLS_export;
22
+ export default _default;