@meistrari/chat-nuxt 1.8.1 → 1.10.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.
- package/README.md +1 -0
- package/dist/module.json +1 -1
- package/dist/runtime/components/MeistrariChatEmbed.vue +3 -0
- package/dist/runtime/components/chat/conversation-creator-filter.d.vue.ts +3 -0
- package/dist/runtime/components/chat/conversation-creator-filter.vue +95 -0
- package/dist/runtime/components/chat/conversation-creator-filter.vue.d.ts +3 -0
- package/dist/runtime/components/chat/conversation-item.d.vue.ts +1 -0
- package/dist/runtime/components/chat/conversation-item.vue +142 -63
- package/dist/runtime/components/chat/conversation-item.vue.d.ts +1 -0
- package/dist/runtime/components/chat/conversation-list.d.vue.ts +2 -0
- package/dist/runtime/components/chat/conversation-list.vue +35 -9
- package/dist/runtime/components/chat/conversation-list.vue.d.ts +2 -0
- package/dist/runtime/components/chat/conversation-search.d.vue.ts +16 -0
- package/dist/runtime/components/chat/conversation-search.vue +35 -0
- package/dist/runtime/components/chat/conversation-search.vue.d.ts +16 -0
- package/dist/runtime/components/chat/mobile/shell/drawer.vue +16 -5
- package/dist/runtime/components/chat/mobile/shell/header.d.vue.ts +4 -4
- package/dist/runtime/components/chat/mobile/shell/header.vue.d.ts +4 -4
- package/dist/runtime/components/chat/mobile/shell/shell.d.vue.ts +14 -14
- package/dist/runtime/components/chat/mobile/shell/shell.vue.d.ts +14 -14
- package/dist/runtime/components/chat/topbar.d.vue.ts +8 -8
- package/dist/runtime/components/chat/topbar.vue +29 -11
- package/dist/runtime/components/chat/topbar.vue.d.ts +8 -8
- package/dist/runtime/composables/useConversations.d.ts +2 -0
- package/dist/runtime/composables/useConversations.js +81 -36
- package/dist/runtime/composables/useEmbedConfig.d.ts +3 -0
- package/dist/runtime/composables/useEmbedConfig.js +4 -0
- package/dist/runtime/embed/components/ChatEmbed.vue +2 -0
- package/dist/runtime/embed/components/ChatEmbedInner.vue +11 -30
- package/dist/runtime/embed/components/configuration/ChatConfigurationContextFilesTab.d.vue.ts +4 -4
- package/dist/runtime/embed/components/configuration/ChatConfigurationContextFilesTab.vue.d.ts +4 -4
- package/dist/runtime/embed/components/configuration/ChatConfigurationMobileShell.d.vue.ts +2 -2
- package/dist/runtime/embed/components/configuration/ChatConfigurationMobileShell.vue.d.ts +2 -2
- package/dist/runtime/server/api/conversations/index.get.js +5 -4
- package/dist/runtime/server/utils/conversation-list.d.ts +4 -0
- package/dist/runtime/server/utils/conversation-list.js +28 -0
- package/dist/runtime/types/chat.d.ts +8 -0
- package/dist/runtime/types/chat.js +4 -0
- package/dist/runtime/types/embed.d.ts +3 -0
- package/dist/runtime/utils/conversation-creator-filter.d.ts +5 -0
- package/dist/runtime/utils/conversation-creator-filter.js +24 -0
- package/dist/runtime/utils/conversation-search.d.ts +8 -0
- package/dist/runtime/utils/conversation-search.js +11 -0
- package/dist/runtime/utils/conversation-title.d.ts +1 -0
- package/dist/runtime/utils/conversation-title.js +6 -0
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { formatRelativeTime } from "../../../../utils/format-time";
|
|
3
3
|
import { conversationListSkeletonRows } from "../../../../utils/conversation-list-skeleton";
|
|
4
|
+
import { filterConversationsByTitle } from "../../../../utils/conversation-search";
|
|
4
5
|
const props = defineProps({
|
|
5
6
|
open: { type: Boolean, required: true },
|
|
6
7
|
conversations: { type: null, required: true },
|
|
@@ -15,6 +16,14 @@ const initial = computed(() => {
|
|
|
15
16
|
const source = props.userName ?? props.userEmail ?? "U";
|
|
16
17
|
return source.charAt(0).toUpperCase();
|
|
17
18
|
});
|
|
19
|
+
const conversationSearch = ref("");
|
|
20
|
+
const filteredConversations = computed(
|
|
21
|
+
() => filterConversationsByTitle(props.conversations, conversationSearch.value, {
|
|
22
|
+
fallbackTitle: "Nova conversa",
|
|
23
|
+
shouldInclude: (conversation) => !conversation.title && conversation.id === props.activeId
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
const hasConversationSearchQuery = computed(() => conversationSearch.value.trim().length > 0);
|
|
18
27
|
function handleSelect(id) {
|
|
19
28
|
emit("select", id);
|
|
20
29
|
emit("close");
|
|
@@ -74,7 +83,7 @@ function handleNew() {
|
|
|
74
83
|
</button>
|
|
75
84
|
</div>
|
|
76
85
|
|
|
77
|
-
<div p-12px>
|
|
86
|
+
<div p-12px flex="~ col" gap-8px>
|
|
78
87
|
<button
|
|
79
88
|
flex items-center justify-center gap-6px
|
|
80
89
|
w-full px-12px py-10px rounded-10px
|
|
@@ -88,6 +97,8 @@ function handleNew() {
|
|
|
88
97
|
Nova conversa
|
|
89
98
|
</span>
|
|
90
99
|
</button>
|
|
100
|
+
<ChatConversationSearch v-model="conversationSearch" />
|
|
101
|
+
<ChatConversationCreatorFilter />
|
|
91
102
|
</div>
|
|
92
103
|
|
|
93
104
|
<div px-14px pt-4px pb-4px>
|
|
@@ -95,7 +106,7 @@ function handleNew() {
|
|
|
95
106
|
text-12px font-medium uppercase text-neutral-400
|
|
96
107
|
style="letter-spacing: 0.5px"
|
|
97
108
|
>
|
|
98
|
-
Recentes
|
|
109
|
+
{{ hasConversationSearchQuery ? "Resultados" : "Recentes" }}
|
|
99
110
|
</span>
|
|
100
111
|
</div>
|
|
101
112
|
|
|
@@ -109,14 +120,14 @@ function handleNew() {
|
|
|
109
120
|
<TelaSkeleton rounded-6px bg-neutral-200 :style="{ width: row.width, height: '13px' }" />
|
|
110
121
|
</div>
|
|
111
122
|
</div>
|
|
112
|
-
<div v-else-if="
|
|
123
|
+
<div v-else-if="filteredConversations.length === 0" p-16px text-center>
|
|
113
124
|
<p text-14px text-neutral-400>
|
|
114
|
-
Nenhuma conversa ainda
|
|
125
|
+
{{ hasConversationSearchQuery ? "Nenhuma conversa encontrada" : "Nenhuma conversa ainda" }}
|
|
115
126
|
</p>
|
|
116
127
|
</div>
|
|
117
128
|
<div v-else flex="~ col" gap-1px>
|
|
118
129
|
<button
|
|
119
|
-
v-for="conv in
|
|
130
|
+
v-for="conv in filteredConversations"
|
|
120
131
|
:key="conv.id"
|
|
121
132
|
flex="~ col" gap-2px
|
|
122
133
|
w-full px-12px py-10px rounded-10px text-left
|
|
@@ -15,24 +15,24 @@ type __VLS_Props = {
|
|
|
15
15
|
};
|
|
16
16
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
17
17
|
delete: () => any;
|
|
18
|
+
openDrawer: () => any;
|
|
19
|
+
openOutdatedSettings: () => any;
|
|
18
20
|
rename: () => any;
|
|
19
21
|
duplicate: () => any;
|
|
20
22
|
export: () => any;
|
|
21
23
|
copyLink: () => any;
|
|
22
24
|
debug: () => any;
|
|
23
25
|
tabChange: (tab: TopbarTab) => any;
|
|
24
|
-
openDrawer: () => any;
|
|
25
|
-
openOutdatedSettings: () => any;
|
|
26
26
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
27
27
|
onDelete?: (() => any) | undefined;
|
|
28
|
+
onOpenDrawer?: (() => any) | undefined;
|
|
29
|
+
onOpenOutdatedSettings?: (() => any) | undefined;
|
|
28
30
|
onRename?: (() => any) | undefined;
|
|
29
31
|
onDuplicate?: (() => any) | undefined;
|
|
30
32
|
onExport?: (() => any) | undefined;
|
|
31
33
|
onCopyLink?: (() => any) | undefined;
|
|
32
34
|
onDebug?: (() => any) | undefined;
|
|
33
35
|
onTabChange?: ((tab: TopbarTab) => any) | undefined;
|
|
34
|
-
onOpenDrawer?: (() => any) | undefined;
|
|
35
|
-
onOpenOutdatedSettings?: (() => any) | undefined;
|
|
36
36
|
}>, {
|
|
37
37
|
showDrawerButton: boolean;
|
|
38
38
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -15,24 +15,24 @@ type __VLS_Props = {
|
|
|
15
15
|
};
|
|
16
16
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
17
17
|
delete: () => any;
|
|
18
|
+
openDrawer: () => any;
|
|
19
|
+
openOutdatedSettings: () => any;
|
|
18
20
|
rename: () => any;
|
|
19
21
|
duplicate: () => any;
|
|
20
22
|
export: () => any;
|
|
21
23
|
copyLink: () => any;
|
|
22
24
|
debug: () => any;
|
|
23
25
|
tabChange: (tab: TopbarTab) => any;
|
|
24
|
-
openDrawer: () => any;
|
|
25
|
-
openOutdatedSettings: () => any;
|
|
26
26
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
27
27
|
onDelete?: (() => any) | undefined;
|
|
28
|
+
onOpenDrawer?: (() => any) | undefined;
|
|
29
|
+
onOpenOutdatedSettings?: (() => any) | undefined;
|
|
28
30
|
onRename?: (() => any) | undefined;
|
|
29
31
|
onDuplicate?: (() => any) | undefined;
|
|
30
32
|
onExport?: (() => any) | undefined;
|
|
31
33
|
onCopyLink?: (() => any) | undefined;
|
|
32
34
|
onDebug?: (() => any) | undefined;
|
|
33
35
|
onTabChange?: ((tab: TopbarTab) => any) | undefined;
|
|
34
|
-
onOpenDrawer?: (() => any) | undefined;
|
|
35
|
-
onOpenOutdatedSettings?: (() => any) | undefined;
|
|
36
36
|
}>, {
|
|
37
37
|
showDrawerButton: boolean;
|
|
38
38
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -50,10 +50,7 @@ type __VLS_Slots = {} & {
|
|
|
50
50
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
51
51
|
delete: () => any;
|
|
52
52
|
cancel: () => any;
|
|
53
|
-
|
|
54
|
-
duplicate: () => any;
|
|
55
|
-
export: () => any;
|
|
56
|
-
saveTitle: () => any;
|
|
53
|
+
settings: () => any;
|
|
57
54
|
send: (content: string, files: FileUploadInput[], model?: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6" | undefined, agentInputs?: ({
|
|
58
55
|
type: "file";
|
|
59
56
|
name: string;
|
|
@@ -66,26 +63,26 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
66
63
|
content: string;
|
|
67
64
|
})[] | undefined) => any;
|
|
68
65
|
"update:model": (value: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6") => any;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
rename: () => any;
|
|
67
|
+
duplicate: () => any;
|
|
68
|
+
export: () => any;
|
|
72
69
|
copyLink: () => any;
|
|
73
70
|
debug: () => any;
|
|
74
71
|
tabChange: (tab: TopbarTab) => any;
|
|
75
72
|
newConversation: () => any;
|
|
76
73
|
switchWorkspace: () => any;
|
|
77
74
|
signout: () => any;
|
|
75
|
+
cancelEditing: () => any;
|
|
78
76
|
dismissOutdatedBanner: () => any;
|
|
77
|
+
saveTitle: () => any;
|
|
79
78
|
selectConversation: (id: string) => any;
|
|
80
79
|
"update:drawerOpen": (value: boolean) => any;
|
|
80
|
+
"update:editTitle": (value: string) => any;
|
|
81
81
|
"update:workspaceSheetOpen": (value: boolean) => any;
|
|
82
82
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
83
83
|
onDelete?: (() => any) | undefined;
|
|
84
84
|
onCancel?: (() => any) | undefined;
|
|
85
|
-
|
|
86
|
-
onDuplicate?: (() => any) | undefined;
|
|
87
|
-
onExport?: (() => any) | undefined;
|
|
88
|
-
onSaveTitle?: (() => any) | undefined;
|
|
85
|
+
onSettings?: (() => any) | undefined;
|
|
89
86
|
onSend?: ((content: string, files: FileUploadInput[], model?: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6" | undefined, agentInputs?: ({
|
|
90
87
|
type: "file";
|
|
91
88
|
name: string;
|
|
@@ -98,18 +95,21 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
98
95
|
content: string;
|
|
99
96
|
})[] | undefined) => any) | undefined;
|
|
100
97
|
"onUpdate:model"?: ((value: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6") => any) | undefined;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
onRename?: (() => any) | undefined;
|
|
99
|
+
onDuplicate?: (() => any) | undefined;
|
|
100
|
+
onExport?: (() => any) | undefined;
|
|
104
101
|
onCopyLink?: (() => any) | undefined;
|
|
105
102
|
onDebug?: (() => any) | undefined;
|
|
106
103
|
onTabChange?: ((tab: TopbarTab) => any) | undefined;
|
|
107
104
|
onNewConversation?: (() => any) | undefined;
|
|
108
105
|
onSwitchWorkspace?: (() => any) | undefined;
|
|
109
106
|
onSignout?: (() => any) | undefined;
|
|
107
|
+
onCancelEditing?: (() => any) | undefined;
|
|
110
108
|
onDismissOutdatedBanner?: (() => any) | undefined;
|
|
109
|
+
onSaveTitle?: (() => any) | undefined;
|
|
111
110
|
onSelectConversation?: ((id: string) => any) | undefined;
|
|
112
111
|
"onUpdate:drawerOpen"?: ((value: boolean) => any) | undefined;
|
|
112
|
+
"onUpdate:editTitle"?: ((value: string) => any) | undefined;
|
|
113
113
|
"onUpdate:workspaceSheetOpen"?: ((value: boolean) => any) | undefined;
|
|
114
114
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
115
115
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -50,10 +50,7 @@ type __VLS_Slots = {} & {
|
|
|
50
50
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
51
51
|
delete: () => any;
|
|
52
52
|
cancel: () => any;
|
|
53
|
-
|
|
54
|
-
duplicate: () => any;
|
|
55
|
-
export: () => any;
|
|
56
|
-
saveTitle: () => any;
|
|
53
|
+
settings: () => any;
|
|
57
54
|
send: (content: string, files: FileUploadInput[], model?: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6" | undefined, agentInputs?: ({
|
|
58
55
|
type: "file";
|
|
59
56
|
name: string;
|
|
@@ -66,26 +63,26 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
66
63
|
content: string;
|
|
67
64
|
})[] | undefined) => any;
|
|
68
65
|
"update:model": (value: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6") => any;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
rename: () => any;
|
|
67
|
+
duplicate: () => any;
|
|
68
|
+
export: () => any;
|
|
72
69
|
copyLink: () => any;
|
|
73
70
|
debug: () => any;
|
|
74
71
|
tabChange: (tab: TopbarTab) => any;
|
|
75
72
|
newConversation: () => any;
|
|
76
73
|
switchWorkspace: () => any;
|
|
77
74
|
signout: () => any;
|
|
75
|
+
cancelEditing: () => any;
|
|
78
76
|
dismissOutdatedBanner: () => any;
|
|
77
|
+
saveTitle: () => any;
|
|
79
78
|
selectConversation: (id: string) => any;
|
|
80
79
|
"update:drawerOpen": (value: boolean) => any;
|
|
80
|
+
"update:editTitle": (value: string) => any;
|
|
81
81
|
"update:workspaceSheetOpen": (value: boolean) => any;
|
|
82
82
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
83
83
|
onDelete?: (() => any) | undefined;
|
|
84
84
|
onCancel?: (() => any) | undefined;
|
|
85
|
-
|
|
86
|
-
onDuplicate?: (() => any) | undefined;
|
|
87
|
-
onExport?: (() => any) | undefined;
|
|
88
|
-
onSaveTitle?: (() => any) | undefined;
|
|
85
|
+
onSettings?: (() => any) | undefined;
|
|
89
86
|
onSend?: ((content: string, files: FileUploadInput[], model?: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6" | undefined, agentInputs?: ({
|
|
90
87
|
type: "file";
|
|
91
88
|
name: string;
|
|
@@ -98,18 +95,21 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
98
95
|
content: string;
|
|
99
96
|
})[] | undefined) => any) | undefined;
|
|
100
97
|
"onUpdate:model"?: ((value: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6") => any) | undefined;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
onRename?: (() => any) | undefined;
|
|
99
|
+
onDuplicate?: (() => any) | undefined;
|
|
100
|
+
onExport?: (() => any) | undefined;
|
|
104
101
|
onCopyLink?: (() => any) | undefined;
|
|
105
102
|
onDebug?: (() => any) | undefined;
|
|
106
103
|
onTabChange?: ((tab: TopbarTab) => any) | undefined;
|
|
107
104
|
onNewConversation?: (() => any) | undefined;
|
|
108
105
|
onSwitchWorkspace?: (() => any) | undefined;
|
|
109
106
|
onSignout?: (() => any) | undefined;
|
|
107
|
+
onCancelEditing?: (() => any) | undefined;
|
|
110
108
|
onDismissOutdatedBanner?: (() => any) | undefined;
|
|
109
|
+
onSaveTitle?: (() => any) | undefined;
|
|
111
110
|
onSelectConversation?: ((id: string) => any) | undefined;
|
|
112
111
|
"onUpdate:drawerOpen"?: ((value: boolean) => any) | undefined;
|
|
112
|
+
"onUpdate:editTitle"?: ((value: string) => any) | undefined;
|
|
113
113
|
"onUpdate:workspaceSheetOpen"?: ((value: boolean) => any) | undefined;
|
|
114
114
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
115
115
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -19,25 +19,25 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
19
19
|
rename: () => any;
|
|
20
20
|
duplicate: () => any;
|
|
21
21
|
export: () => any;
|
|
22
|
-
saveTitle: () => any;
|
|
23
|
-
"update:isEditing": (value: boolean) => any;
|
|
24
|
-
"update:editTitle": (value: string) => any;
|
|
25
|
-
cancelEditing: () => any;
|
|
26
22
|
copyLink: () => any;
|
|
27
23
|
debug: () => any;
|
|
28
24
|
tabChange: (tab: TopbarTab) => any;
|
|
25
|
+
cancelEditing: () => any;
|
|
26
|
+
saveTitle: () => any;
|
|
27
|
+
"update:editTitle": (value: string) => any;
|
|
28
|
+
"update:isEditing": (value: boolean) => any;
|
|
29
29
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
30
30
|
onDelete?: (() => any) | undefined;
|
|
31
31
|
onRename?: (() => any) | undefined;
|
|
32
32
|
onDuplicate?: (() => any) | undefined;
|
|
33
33
|
onExport?: (() => any) | undefined;
|
|
34
|
-
onSaveTitle?: (() => any) | undefined;
|
|
35
|
-
"onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
|
|
36
|
-
"onUpdate:editTitle"?: ((value: string) => any) | undefined;
|
|
37
|
-
onCancelEditing?: (() => any) | undefined;
|
|
38
34
|
onCopyLink?: (() => any) | undefined;
|
|
39
35
|
onDebug?: (() => any) | undefined;
|
|
40
36
|
onTabChange?: ((tab: TopbarTab) => any) | undefined;
|
|
37
|
+
onCancelEditing?: (() => any) | undefined;
|
|
38
|
+
onSaveTitle?: (() => any) | undefined;
|
|
39
|
+
"onUpdate:editTitle"?: ((value: string) => any) | undefined;
|
|
40
|
+
"onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
|
|
41
41
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
42
42
|
declare const _default: typeof __VLS_export;
|
|
43
43
|
export default _default;
|
|
@@ -19,6 +19,7 @@ const props = defineProps({
|
|
|
19
19
|
const emit = defineEmits(["update:isEditing", "update:editTitle", "saveTitle", "cancelEditing", "rename", "duplicate", "export", "copyLink", "debug", "delete", "tabChange"]);
|
|
20
20
|
const titleInputRef = ref(null);
|
|
21
21
|
const currentTab = computed(() => props.activeTab ?? "chat");
|
|
22
|
+
const titleInputWidth = computed(() => `${Math.max(props.editTitle.length + 2, 8)}ch`);
|
|
22
23
|
const headerMenuItems = computed(() => {
|
|
23
24
|
const items = [
|
|
24
25
|
{
|
|
@@ -87,19 +88,36 @@ watch(() => props.isEditing, (editing) => {
|
|
|
87
88
|
:style="{ left: 'var(--chat-panel-offset)' }"
|
|
88
89
|
>
|
|
89
90
|
<div flex="~ col 1" gap-4px min-w-0>
|
|
90
|
-
<
|
|
91
|
+
<div
|
|
91
92
|
v-if="isEditing"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
93
|
+
flex items-center
|
|
94
|
+
text-primary
|
|
95
|
+
w-fit max-w-full
|
|
96
|
+
pb-1px
|
|
97
|
+
b-b=".5px solid #A3A3A3"
|
|
98
|
+
:style="{ width: titleInputWidth }"
|
|
99
|
+
>
|
|
100
|
+
<input
|
|
101
|
+
ref="titleInputRef"
|
|
102
|
+
:value="editTitle"
|
|
103
|
+
type="text"
|
|
104
|
+
autocomplete="off"
|
|
105
|
+
aria-label="Nome da conversa"
|
|
106
|
+
w-full min-w-0 max-w-full
|
|
107
|
+
bg-transparent border-none outline-none
|
|
108
|
+
text-16px font-580 text-primary leading-20px tracking="-.2px"
|
|
109
|
+
p-0
|
|
110
|
+
@input="emit('update:editTitle', $event.target.value)"
|
|
111
|
+
@keydown="handleTitleKeydown"
|
|
112
|
+
@blur="emit('saveTitle')"
|
|
113
|
+
>
|
|
114
|
+
</div>
|
|
115
|
+
<p
|
|
116
|
+
v-else
|
|
117
|
+
text-16px font-580 text-primary leading-20px tracking="-.2px"
|
|
118
|
+
truncate cursor-text
|
|
119
|
+
@dblclick.prevent.stop="emit('rename')"
|
|
101
120
|
>
|
|
102
|
-
<p v-else text-16px font-580 text-primary leading-20px tracking="-.2px" truncate>
|
|
103
121
|
{{ capitalizeFirst(title) }}<span v-if="generatingTitle" class="typing-cursor">|</span>
|
|
104
122
|
</p>
|
|
105
123
|
|
|
@@ -19,25 +19,25 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
19
19
|
rename: () => any;
|
|
20
20
|
duplicate: () => any;
|
|
21
21
|
export: () => any;
|
|
22
|
-
saveTitle: () => any;
|
|
23
|
-
"update:isEditing": (value: boolean) => any;
|
|
24
|
-
"update:editTitle": (value: string) => any;
|
|
25
|
-
cancelEditing: () => any;
|
|
26
22
|
copyLink: () => any;
|
|
27
23
|
debug: () => any;
|
|
28
24
|
tabChange: (tab: TopbarTab) => any;
|
|
25
|
+
cancelEditing: () => any;
|
|
26
|
+
saveTitle: () => any;
|
|
27
|
+
"update:editTitle": (value: string) => any;
|
|
28
|
+
"update:isEditing": (value: boolean) => any;
|
|
29
29
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
30
30
|
onDelete?: (() => any) | undefined;
|
|
31
31
|
onRename?: (() => any) | undefined;
|
|
32
32
|
onDuplicate?: (() => any) | undefined;
|
|
33
33
|
onExport?: (() => any) | undefined;
|
|
34
|
-
onSaveTitle?: (() => any) | undefined;
|
|
35
|
-
"onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
|
|
36
|
-
"onUpdate:editTitle"?: ((value: string) => any) | undefined;
|
|
37
|
-
onCancelEditing?: (() => any) | undefined;
|
|
38
34
|
onCopyLink?: (() => any) | undefined;
|
|
39
35
|
onDebug?: (() => any) | undefined;
|
|
40
36
|
onTabChange?: ((tab: TopbarTab) => any) | undefined;
|
|
37
|
+
onCancelEditing?: (() => any) | undefined;
|
|
38
|
+
onSaveTitle?: (() => any) | undefined;
|
|
39
|
+
"onUpdate:editTitle"?: ((value: string) => any) | undefined;
|
|
40
|
+
"onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
|
|
41
41
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
42
42
|
declare const _default: typeof __VLS_export;
|
|
43
43
|
export default _default;
|
|
@@ -14,5 +14,7 @@ export declare function useConversations(): {
|
|
|
14
14
|
deleteConversation: (id: string) => Promise<boolean>;
|
|
15
15
|
renameConversation: (id: string, title: string) => Promise<boolean>;
|
|
16
16
|
duplicateConversation: (id: string) => Promise<ConversationWithMessages | null>;
|
|
17
|
+
conversationCreatorFilter: any;
|
|
18
|
+
conversationCreatorFilterCounts: any;
|
|
17
19
|
updateConversationInList: (updated: Conversation | DeepReadonly<Conversation>) => void;
|
|
18
20
|
};
|
|
@@ -24,10 +24,19 @@ export function mergeFetchedConversations(fetchedConversations, localConversatio
|
|
|
24
24
|
}
|
|
25
25
|
return sortConversationsByUpdatedAt([...mergedById.values()]);
|
|
26
26
|
}
|
|
27
|
+
function bucketValue(bucket, key, fallback) {
|
|
28
|
+
return bucket.value[key] ?? fallback;
|
|
29
|
+
}
|
|
30
|
+
function setBucketValue(bucket, key, value) {
|
|
31
|
+
bucket.value = {
|
|
32
|
+
...bucket.value,
|
|
33
|
+
[key]: value
|
|
34
|
+
};
|
|
35
|
+
}
|
|
27
36
|
export function useConversations() {
|
|
28
37
|
const chatApi = useChatApi();
|
|
29
38
|
const embedConfig = useEmbedConfig();
|
|
30
|
-
const { activeOrganization } = useChatAuth();
|
|
39
|
+
const { user: authUser, activeOrganization } = useChatAuth();
|
|
31
40
|
const conversationBuckets = useState("conversations", () => ({}));
|
|
32
41
|
const loadingBuckets = useState("conversations-loading", () => ({}));
|
|
33
42
|
const errorBuckets = useState("conversations-error", () => ({}));
|
|
@@ -35,12 +44,27 @@ export function useConversations() {
|
|
|
35
44
|
const mutationVersionBuckets = useState("conversations-mutation-version", () => ({}));
|
|
36
45
|
const deletedIdBuckets = useState("conversations-deleted-ids", () => ({}));
|
|
37
46
|
const mutatedIdBuckets = useState("conversations-mutated-ids", () => ({}));
|
|
47
|
+
const conversationCreatorFilter = useState(
|
|
48
|
+
"conversation-creator-filter",
|
|
49
|
+
() => embedConfig?.defaultConversationCreatorFilter?.value ?? "all"
|
|
50
|
+
);
|
|
38
51
|
const isTelaAgentMode = computed(() => !!embedConfig?.telaAgentId.value);
|
|
39
|
-
const
|
|
52
|
+
const runtimeScope = computed(() => resolveChatStateScope(
|
|
40
53
|
embedConfig?.workspaceId.value || activeOrganization.value?.id,
|
|
41
54
|
embedConfig?.telaAgentId.value,
|
|
42
55
|
embedConfig?.conversationScope?.value
|
|
43
56
|
));
|
|
57
|
+
const workspaceScope = computed(() => `${runtimeScope.value}:creator:${conversationCreatorFilter.value}`);
|
|
58
|
+
const conversationBucketKey = (filter) => `${runtimeScope.value}:creator:${filter}`;
|
|
59
|
+
const conversationCreatorFilterCounts = computed(() => {
|
|
60
|
+
const allConversations = conversationBuckets.value[conversationBucketKey("all")] ?? [];
|
|
61
|
+
const mineConversations = conversationBuckets.value[conversationBucketKey("mine")];
|
|
62
|
+
const authUserId = authUser.value?.id;
|
|
63
|
+
return {
|
|
64
|
+
all: allConversations.length,
|
|
65
|
+
mine: mineConversations?.length ?? (authUserId ? allConversations.filter((conversation) => conversation.userId === authUserId).length : 0)
|
|
66
|
+
};
|
|
67
|
+
});
|
|
44
68
|
const conversations = computed({
|
|
45
69
|
get: () => conversationBuckets.value[workspaceScope.value] ?? [],
|
|
46
70
|
set: (value) => {
|
|
@@ -95,15 +119,6 @@ export function useConversations() {
|
|
|
95
119
|
};
|
|
96
120
|
}
|
|
97
121
|
});
|
|
98
|
-
const hasFetched = computed({
|
|
99
|
-
get: () => fetchedBuckets.value[workspaceScope.value] ?? false,
|
|
100
|
-
set: (value) => {
|
|
101
|
-
fetchedBuckets.value = {
|
|
102
|
-
...fetchedBuckets.value,
|
|
103
|
-
[workspaceScope.value]: value
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
122
|
function markMutated(id) {
|
|
108
123
|
mutationVersion.value = mutationVersion.value + 1;
|
|
109
124
|
if (id) {
|
|
@@ -114,6 +129,33 @@ export function useConversations() {
|
|
|
114
129
|
conversations.value = sortConversationsByUpdatedAt(nextConversations);
|
|
115
130
|
markMutated(mutatedId);
|
|
116
131
|
}
|
|
132
|
+
function commitConversationsToScope(scope, nextConversations, mutatedId) {
|
|
133
|
+
setBucketValue(conversationBuckets, scope, sortConversationsByUpdatedAt(nextConversations));
|
|
134
|
+
setBucketValue(mutationVersionBuckets, scope, bucketValue(mutationVersionBuckets, scope, 0) + 1);
|
|
135
|
+
if (mutatedId) {
|
|
136
|
+
setBucketValue(mutatedIdBuckets, scope, [
|
|
137
|
+
.../* @__PURE__ */ new Set([...bucketValue(mutatedIdBuckets, scope, []), mutatedId])
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function upsertCreatedConversation(conversation) {
|
|
142
|
+
const allScope = conversationBucketKey("all");
|
|
143
|
+
const allConversations = bucketValue(conversationBuckets, allScope, []);
|
|
144
|
+
commitConversationsToScope(
|
|
145
|
+
allScope,
|
|
146
|
+
[conversation, ...allConversations.filter((item) => item.id !== conversation.id)],
|
|
147
|
+
conversation.id
|
|
148
|
+
);
|
|
149
|
+
if (authUser.value?.id === conversation.userId || conversationCreatorFilter.value === "mine") {
|
|
150
|
+
const mineScope = conversationBucketKey("mine");
|
|
151
|
+
const mineConversations = bucketValue(conversationBuckets, mineScope, []);
|
|
152
|
+
commitConversationsToScope(
|
|
153
|
+
mineScope,
|
|
154
|
+
[conversation, ...mineConversations.filter((item) => item.id !== conversation.id)],
|
|
155
|
+
conversation.id
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
117
159
|
function addDeletedConversationId(id) {
|
|
118
160
|
deletedConversationIds.value = [.../* @__PURE__ */ new Set([...deletedConversationIds.value, id])];
|
|
119
161
|
markMutated();
|
|
@@ -122,48 +164,49 @@ export function useConversations() {
|
|
|
122
164
|
deletedConversationIds.value = deletedConversationIds.value.filter((deletedId) => deletedId !== id);
|
|
123
165
|
markMutated();
|
|
124
166
|
}
|
|
125
|
-
function pruneDeletedConversationIds(serverConversations) {
|
|
126
|
-
const returnedIds = new Set(serverConversations.map((conversation) => conversation.id));
|
|
127
|
-
deletedConversationIds.value = deletedConversationIds.value.filter((id) => returnedIds.has(id));
|
|
128
|
-
}
|
|
129
167
|
function cloneAppliedSettingsSnapshot(snapshot) {
|
|
130
168
|
if (!snapshot)
|
|
131
169
|
return null;
|
|
132
170
|
return JSON.parse(JSON.stringify(snapshot));
|
|
133
171
|
}
|
|
134
172
|
const fetchConversations = async (options = {}) => {
|
|
135
|
-
|
|
173
|
+
const requestScope = workspaceScope.value;
|
|
174
|
+
const requestCreatorFilter = conversationCreatorFilter.value;
|
|
175
|
+
if (bucketValue(loadingBuckets, requestScope, false) || bucketValue(fetchedBuckets, requestScope, false) && !options.force) {
|
|
136
176
|
return;
|
|
137
177
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const mutationVersionAtStart =
|
|
178
|
+
setBucketValue(loadingBuckets, requestScope, true);
|
|
179
|
+
setBucketValue(errorBuckets, requestScope, null);
|
|
180
|
+
const mutationVersionAtStart = bucketValue(mutationVersionBuckets, requestScope, 0);
|
|
141
181
|
try {
|
|
142
182
|
const data = await $fetch(
|
|
143
183
|
chatApi.path("/conversations"),
|
|
144
|
-
chatApi.withChatHeaders()
|
|
184
|
+
chatApi.withChatHeaders(requestCreatorFilter === "mine" ? { query: { creator: "me" } } : void 0)
|
|
145
185
|
);
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
186
|
+
const currentDeletedIds = bucketValue(deletedIdBuckets, requestScope, []);
|
|
187
|
+
const currentMutatedIds = bucketValue(mutatedIdBuckets, requestScope, []);
|
|
188
|
+
const visibleData = data.filter((conversation) => !currentDeletedIds.includes(conversation.id));
|
|
189
|
+
if (bucketValue(mutationVersionBuckets, requestScope, 0) === mutationVersionAtStart) {
|
|
190
|
+
setBucketValue(conversationBuckets, requestScope, sortConversationsByUpdatedAt(visibleData));
|
|
191
|
+
setBucketValue(mutatedIdBuckets, requestScope, []);
|
|
150
192
|
} else {
|
|
151
|
-
|
|
193
|
+
setBucketValue(conversationBuckets, requestScope, mergeFetchedConversations(
|
|
152
194
|
visibleData,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
);
|
|
157
|
-
|
|
195
|
+
bucketValue(conversationBuckets, requestScope, []),
|
|
196
|
+
currentDeletedIds,
|
|
197
|
+
currentMutatedIds
|
|
198
|
+
));
|
|
199
|
+
setBucketValue(mutatedIdBuckets, requestScope, []);
|
|
158
200
|
}
|
|
159
|
-
|
|
160
|
-
|
|
201
|
+
const returnedIds = new Set(data.map((conversation) => conversation.id));
|
|
202
|
+
setBucketValue(deletedIdBuckets, requestScope, currentDeletedIds.filter((id) => returnedIds.has(id)));
|
|
203
|
+
setBucketValue(fetchedBuckets, requestScope, true);
|
|
161
204
|
} catch (err) {
|
|
162
205
|
const message = err instanceof Error ? err.message : "Erro ao carregar conversas";
|
|
163
|
-
|
|
206
|
+
setBucketValue(errorBuckets, requestScope, message);
|
|
164
207
|
Sentry.captureException(err);
|
|
165
208
|
} finally {
|
|
166
|
-
|
|
209
|
+
setBucketValue(loadingBuckets, requestScope, false);
|
|
167
210
|
}
|
|
168
211
|
};
|
|
169
212
|
const createConversation = async (options) => {
|
|
@@ -176,7 +219,7 @@ export function useConversations() {
|
|
|
176
219
|
body: !isTelaAgentMode.value && options?.model ? { model: options.model } : void 0
|
|
177
220
|
})
|
|
178
221
|
);
|
|
179
|
-
|
|
222
|
+
upsertCreatedConversation(conversation);
|
|
180
223
|
return conversation;
|
|
181
224
|
} catch (err) {
|
|
182
225
|
const message = err instanceof Error ? err.message : "Erro ao criar conversa";
|
|
@@ -272,7 +315,7 @@ export function useConversations() {
|
|
|
272
315
|
method: "POST"
|
|
273
316
|
})
|
|
274
317
|
);
|
|
275
|
-
|
|
318
|
+
upsertCreatedConversation(duplicated);
|
|
276
319
|
statusToast.update({
|
|
277
320
|
text: "Conversa duplicada",
|
|
278
321
|
icon: "i-ph-check"
|
|
@@ -297,6 +340,8 @@ export function useConversations() {
|
|
|
297
340
|
deleteConversation,
|
|
298
341
|
renameConversation,
|
|
299
342
|
duplicateConversation,
|
|
343
|
+
conversationCreatorFilter,
|
|
344
|
+
conversationCreatorFilterCounts,
|
|
300
345
|
updateConversationInList
|
|
301
346
|
};
|
|
302
347
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Component, DeepReadonly, MaybeRefOrGetter, Ref } from 'vue';
|
|
2
|
+
import type { ConversationCreatorFilter } from '../types/chat.js';
|
|
2
3
|
import type { TelaAgentExecutionInput } from '../types/tela-agent.js';
|
|
3
4
|
import type { WorkspaceSettings } from '../types/workspace-settings-data.js';
|
|
4
5
|
import type { ChatLoadingMessageMode } from '../utils/chat-loading-messages.js';
|
|
@@ -7,6 +8,7 @@ export type EmbedConfig = {
|
|
|
7
8
|
workspaceId: Ref<string>;
|
|
8
9
|
telaAgentId: Ref<string | null>;
|
|
9
10
|
conversationScope: Ref<string | null>;
|
|
11
|
+
defaultConversationCreatorFilter: Ref<ConversationCreatorFilter>;
|
|
10
12
|
telaAgentInputs: Ref<ConfiguredTelaAgentInputs>;
|
|
11
13
|
workspaceSettings: Ref<DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null | undefined>;
|
|
12
14
|
hideSidebar: Ref<boolean>;
|
|
@@ -20,6 +22,7 @@ type EmbedConfigInput = {
|
|
|
20
22
|
workspaceId: MaybeRefOrGetter<string>;
|
|
21
23
|
telaAgentId?: MaybeRefOrGetter<string | null | undefined>;
|
|
22
24
|
conversationScope?: MaybeRefOrGetter<string | null | undefined>;
|
|
25
|
+
defaultConversationCreatorFilter?: MaybeRefOrGetter<ConversationCreatorFilter | null | undefined>;
|
|
23
26
|
telaAgentInputs?: MaybeRefOrGetter<ConfiguredTelaAgentInputs>;
|
|
24
27
|
workspaceSettings?: MaybeRefOrGetter<DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null | undefined>;
|
|
25
28
|
hideSidebar?: MaybeRefOrGetter<boolean | undefined>;
|
|
@@ -11,6 +11,7 @@ function useGlobalEmbedConfigState() {
|
|
|
11
11
|
workspaceId: useState("chat-embed-config-workspace-id", () => ""),
|
|
12
12
|
telaAgentId: useState("chat-embed-config-tela-agent-id", () => null),
|
|
13
13
|
conversationScope: useState("chat-embed-config-conversation-scope", () => null),
|
|
14
|
+
defaultConversationCreatorFilter: useState("chat-embed-config-default-conversation-creator-filter", () => void 0),
|
|
14
15
|
telaAgentInputs: useState("chat-embed-config-tela-agent-inputs", () => void 0),
|
|
15
16
|
workspaceSettings: useState("chat-embed-config-workspace-settings", () => void 0),
|
|
16
17
|
hideSidebar: useState("chat-embed-config-hide-sidebar", () => void 0),
|
|
@@ -26,6 +27,7 @@ export function provideEmbedConfig(input, options = {}) {
|
|
|
26
27
|
workspaceId: computed(() => toValue(input.workspaceId)),
|
|
27
28
|
telaAgentId: computed(() => toValue(input.telaAgentId) ?? null),
|
|
28
29
|
conversationScope: computed(() => normalizeConversationScope(toValue(input.conversationScope))),
|
|
30
|
+
defaultConversationCreatorFilter: computed(() => toValue(input.defaultConversationCreatorFilter) ?? "all"),
|
|
29
31
|
telaAgentInputs: computed(() => toValue(input.telaAgentInputs)),
|
|
30
32
|
workspaceSettings: computed(() => toValue(input.workspaceSettings)),
|
|
31
33
|
hideSidebar: computed(() => toValue(input.hideSidebar) ?? true),
|
|
@@ -42,6 +44,7 @@ export function provideEmbedConfig(input, options = {}) {
|
|
|
42
44
|
globalConfig.workspaceId.value = config.workspaceId.value;
|
|
43
45
|
globalConfig.telaAgentId.value = config.telaAgentId.value;
|
|
44
46
|
globalConfig.conversationScope.value = config.conversationScope.value;
|
|
47
|
+
globalConfig.defaultConversationCreatorFilter.value = config.defaultConversationCreatorFilter.value;
|
|
45
48
|
globalConfig.telaAgentInputs.value = config.telaAgentInputs.value;
|
|
46
49
|
globalConfig.workspaceSettings.value = config.workspaceSettings.value;
|
|
47
50
|
globalConfig.hideSidebar.value = config.hideSidebar.value;
|
|
@@ -65,6 +68,7 @@ export function useEmbedConfig() {
|
|
|
65
68
|
workspaceId: computed(() => globalConfig.workspaceId.value),
|
|
66
69
|
telaAgentId: computed(() => globalConfig.telaAgentId.value),
|
|
67
70
|
conversationScope: computed(() => globalConfig.conversationScope.value),
|
|
71
|
+
defaultConversationCreatorFilter: computed(() => globalConfig.defaultConversationCreatorFilter.value ?? "all"),
|
|
68
72
|
telaAgentInputs: computed(() => globalConfig.telaAgentInputs.value),
|
|
69
73
|
workspaceSettings: computed(() => globalConfig.workspaceSettings.value),
|
|
70
74
|
hideSidebar: computed(() => globalConfig.hideSidebar.value ?? true),
|