@meistrari/chat-nuxt 1.11.0 → 1.13.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/dist/module.json +1 -1
- package/dist/module.mjs +15 -0
- package/dist/runtime/components/chat/conversation-item.d.vue.ts +6 -1
- package/dist/runtime/components/chat/conversation-item.vue +30 -141
- package/dist/runtime/components/chat/conversation-item.vue.d.ts +6 -1
- package/dist/runtime/components/chat/conversation-list.d.vue.ts +1 -0
- package/dist/runtime/components/chat/conversation-list.vue +300 -72
- package/dist/runtime/components/chat/conversation-list.vue.d.ts +1 -0
- package/dist/runtime/components/chat/conversation-new-group-button.d.vue.ts +7 -0
- package/dist/runtime/components/chat/conversation-new-group-button.vue +90 -0
- package/dist/runtime/components/chat/conversation-new-group-button.vue.d.ts +7 -0
- package/dist/runtime/components/chat/conversation-new-group-popover-content.d.vue.ts +23 -0
- package/dist/runtime/components/chat/conversation-new-group-popover-content.vue +75 -0
- package/dist/runtime/components/chat/conversation-new-group-popover-content.vue.d.ts +23 -0
- package/dist/runtime/components/chat/mobile/shell/drawer.d.vue.ts +2 -2
- package/dist/runtime/components/chat/mobile/shell/drawer.vue +370 -41
- package/dist/runtime/components/chat/mobile/shell/drawer.vue.d.ts +2 -2
- package/dist/runtime/components/chat/mobile/shell/shell.d.vue.ts +6 -6
- package/dist/runtime/components/chat/mobile/shell/shell.vue +1 -1
- package/dist/runtime/components/chat/mobile/shell/shell.vue.d.ts +6 -6
- package/dist/runtime/components/chat/reasoning-message.vue +4 -1
- package/dist/runtime/components/chat/topbar.d.vue.ts +2 -2
- package/dist/runtime/components/chat/topbar.vue.d.ts +2 -2
- package/dist/runtime/composables/useConversationGroups.d.ts +12 -0
- package/dist/runtime/composables/useConversationGroups.js +160 -0
- package/dist/runtime/composables/useConversationItem.d.ts +48 -0
- package/dist/runtime/composables/useConversationItem.js +176 -0
- package/dist/runtime/composables/useConversationList.d.ts +128 -0
- package/dist/runtime/composables/useConversationList.js +553 -0
- package/dist/runtime/composables/useConversations.d.ts +2 -0
- package/dist/runtime/composables/useConversations.js +45 -1
- package/dist/runtime/composables/usePendingConversationGroup.d.ts +5 -0
- package/dist/runtime/composables/usePendingConversationGroup.js +33 -0
- package/dist/runtime/composables/useVerbConjugation.d.ts +1 -0
- package/dist/runtime/composables/useVerbConjugation.js +14 -1
- package/dist/runtime/embed/components/ChatConfigurationModal.d.vue.ts +1 -1
- package/dist/runtime/embed/components/ChatConfigurationModal.vue.d.ts +1 -1
- package/dist/runtime/embed/components/ChatEmbedInner.vue +24 -5
- package/dist/runtime/server/api/chat/conversations/[id]/group.patch.d.ts +1 -0
- package/dist/runtime/server/api/chat/conversations/[id]/group.patch.js +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/[groupId]/index.delete.d.ts +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/[groupId]/index.delete.js +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/[groupId]/index.patch.d.ts +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/[groupId]/index.patch.js +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/index.get.d.ts +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/index.get.js +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/index.post.d.ts +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/index.post.js +1 -0
- package/dist/runtime/server/api/conversations/[id]/duplicate.post.js +1 -0
- package/dist/runtime/server/api/conversations/[id]/group.patch.d.ts +2 -0
- package/dist/runtime/server/api/conversations/[id]/group.patch.js +46 -0
- package/dist/runtime/server/api/conversations/[id]/messages/[messageId]/retry.post.js +2 -0
- package/dist/runtime/server/api/conversations/[id]/messages/index.get.js +26 -4
- package/dist/runtime/server/api/conversations/groups/[groupId]/index.delete.d.ts +4 -0
- package/dist/runtime/server/api/conversations/groups/[groupId]/index.delete.js +25 -0
- package/dist/runtime/server/api/conversations/groups/[groupId]/index.patch.d.ts +2 -0
- package/dist/runtime/server/api/conversations/groups/[groupId]/index.patch.js +30 -0
- package/dist/runtime/server/api/conversations/groups/index.get.d.ts +2 -0
- package/dist/runtime/server/api/conversations/groups/index.get.js +13 -0
- package/dist/runtime/server/api/conversations/groups/index.post.d.ts +2 -0
- package/dist/runtime/server/api/conversations/groups/index.post.js +26 -0
- package/dist/runtime/server/api/conversations/index.post.js +1 -0
- package/dist/runtime/server/db/schema/conversation-groups.d.ts +143 -0
- package/dist/runtime/server/db/schema/conversation-groups.js +20 -0
- package/dist/runtime/server/db/schema/conversations.d.ts +17 -0
- package/dist/runtime/server/db/schema/conversations.js +3 -0
- package/dist/runtime/server/db/schema/index.d.ts +1 -0
- package/dist/runtime/server/db/schema/index.js +1 -0
- package/dist/runtime/server/db/schema/messages.d.ts +34 -0
- package/dist/runtime/server/db/schema/messages.js +3 -1
- package/dist/runtime/server/utils/conversation-group.d.ts +4 -0
- package/dist/runtime/server/utils/conversation-group.js +48 -0
- package/dist/runtime/server/utils/conversation-message-sync.d.ts +1 -1
- package/dist/runtime/server/utils/conversation-message-sync.js +2 -2
- package/dist/runtime/server/utils/tela-agent-api.d.ts +3 -1
- package/dist/runtime/server/utils/tela-agent-api.js +285 -26
- package/dist/runtime/server/utils/tela-agent-session.d.ts +14 -4
- package/dist/runtime/server/utils/tela-agent-session.js +57 -22
- package/dist/runtime/types/chat.d.ts +2 -1
- package/dist/runtime/types/tela-agent.d.ts +155 -43
- package/dist/runtime/types/tela-agent.js +49 -11
- package/dist/runtime/utils/conversation-groups.d.ts +18 -0
- package/dist/runtime/utils/conversation-groups.js +30 -0
- package/drizzle/0016_dry_aaron_stack.sql +16 -0
- package/drizzle/0017_typical_dexter_bennett.sql +2 -0
- package/drizzle/meta/0016_snapshot.json +887 -0
- package/drizzle/meta/0017_snapshot.json +899 -0
- package/drizzle/meta/_journal.json +14 -0
- package/package.json +1 -1
|
@@ -19,11 +19,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
19
19
|
rename: () => any;
|
|
20
20
|
duplicate: () => any;
|
|
21
21
|
export: () => any;
|
|
22
|
+
copyLink: () => any;
|
|
22
23
|
"update:isEditing": (value: boolean) => any;
|
|
23
24
|
"update:editTitle": (value: string) => any;
|
|
24
25
|
saveTitle: () => any;
|
|
25
26
|
cancelEditing: () => any;
|
|
26
|
-
copyLink: () => any;
|
|
27
27
|
debug: () => any;
|
|
28
28
|
tabChange: (tab: TopbarTab) => any;
|
|
29
29
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
@@ -31,11 +31,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
31
31
|
onRename?: (() => any) | undefined;
|
|
32
32
|
onDuplicate?: (() => any) | undefined;
|
|
33
33
|
onExport?: (() => any) | undefined;
|
|
34
|
+
onCopyLink?: (() => any) | undefined;
|
|
34
35
|
"onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
|
|
35
36
|
"onUpdate:editTitle"?: ((value: string) => any) | undefined;
|
|
36
37
|
onSaveTitle?: (() => any) | undefined;
|
|
37
38
|
onCancelEditing?: (() => any) | undefined;
|
|
38
|
-
onCopyLink?: (() => any) | undefined;
|
|
39
39
|
onDebug?: (() => any) | undefined;
|
|
40
40
|
onTabChange?: ((tab: TopbarTab) => any) | undefined;
|
|
41
41
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ConversationGroup } from '../types/chat.js';
|
|
2
|
+
export declare function useConversationGroups(): {
|
|
3
|
+
groups: any;
|
|
4
|
+
loading: any;
|
|
5
|
+
error: any;
|
|
6
|
+
fetchGroups: (options?: {
|
|
7
|
+
force?: boolean;
|
|
8
|
+
}) => Promise<void>;
|
|
9
|
+
createGroup: (name: string) => Promise<ConversationGroup | null>;
|
|
10
|
+
renameGroup: (groupId: string, name: string) => Promise<boolean>;
|
|
11
|
+
deleteGroup: (groupId: string) => Promise<boolean>;
|
|
12
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import * as Sentry from "@sentry/nuxt";
|
|
2
|
+
import { useChatAuth } from "#chat-auth";
|
|
3
|
+
import { resolveChatStateScope } from "../utils/tela-chat.js";
|
|
4
|
+
function sortConversationGroups(groups) {
|
|
5
|
+
return [...groups].sort((a, b) => {
|
|
6
|
+
const createdDelta = new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
|
|
7
|
+
if (createdDelta !== 0)
|
|
8
|
+
return createdDelta;
|
|
9
|
+
return a.name.localeCompare(b.name);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export function useConversationGroups() {
|
|
13
|
+
const chatApi = useChatApi();
|
|
14
|
+
const embedConfig = useEmbedConfig();
|
|
15
|
+
const { activeOrganization } = useChatAuth();
|
|
16
|
+
const groupBuckets = useState("conversation-groups", () => ({}));
|
|
17
|
+
const loadingBuckets = useState("conversation-groups-loading", () => ({}));
|
|
18
|
+
const fetchedBuckets = useState("conversation-groups-fetched", () => ({}));
|
|
19
|
+
const errorBuckets = useState("conversation-groups-error", () => ({}));
|
|
20
|
+
const runtimeScope = computed(() => resolveChatStateScope(
|
|
21
|
+
embedConfig?.workspaceId.value || activeOrganization.value?.id,
|
|
22
|
+
embedConfig?.telaAgentId.value,
|
|
23
|
+
embedConfig?.conversationScope?.value
|
|
24
|
+
));
|
|
25
|
+
const groups = computed({
|
|
26
|
+
get: () => groupBuckets.value[runtimeScope.value] ?? [],
|
|
27
|
+
set: (value) => {
|
|
28
|
+
groupBuckets.value = {
|
|
29
|
+
...groupBuckets.value,
|
|
30
|
+
[runtimeScope.value]: sortConversationGroups(value)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const loading = computed({
|
|
35
|
+
get: () => loadingBuckets.value[runtimeScope.value] ?? false,
|
|
36
|
+
set: (value) => {
|
|
37
|
+
loadingBuckets.value = {
|
|
38
|
+
...loadingBuckets.value,
|
|
39
|
+
[runtimeScope.value]: value
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const error = computed({
|
|
44
|
+
get: () => errorBuckets.value[runtimeScope.value] ?? null,
|
|
45
|
+
set: (value) => {
|
|
46
|
+
errorBuckets.value = {
|
|
47
|
+
...errorBuckets.value,
|
|
48
|
+
[runtimeScope.value]: value
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
function setFetched(value) {
|
|
53
|
+
fetchedBuckets.value = {
|
|
54
|
+
...fetchedBuckets.value,
|
|
55
|
+
[runtimeScope.value]: value
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function upsertGroup(group) {
|
|
59
|
+
groups.value = [
|
|
60
|
+
group,
|
|
61
|
+
...groups.value.filter((item) => item.id !== group.id)
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
function removeGroup(groupId) {
|
|
65
|
+
groups.value = groups.value.filter((group) => group.id !== groupId);
|
|
66
|
+
}
|
|
67
|
+
const fetchGroups = async (options = {}) => {
|
|
68
|
+
if (loading.value || fetchedBuckets.value[runtimeScope.value] && !options.force) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
loading.value = true;
|
|
72
|
+
error.value = null;
|
|
73
|
+
try {
|
|
74
|
+
groups.value = await $fetch(
|
|
75
|
+
chatApi.path("/conversations/groups"),
|
|
76
|
+
chatApi.withChatHeaders()
|
|
77
|
+
);
|
|
78
|
+
setFetched(true);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
error.value = err instanceof Error ? err.message : "Erro ao carregar pastas";
|
|
81
|
+
Sentry.captureException(err);
|
|
82
|
+
} finally {
|
|
83
|
+
loading.value = false;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const createGroup = async (name) => {
|
|
87
|
+
error.value = null;
|
|
88
|
+
try {
|
|
89
|
+
const group = await $fetch(
|
|
90
|
+
chatApi.path("/conversations/groups"),
|
|
91
|
+
chatApi.withChatHeaders({
|
|
92
|
+
method: "POST",
|
|
93
|
+
body: { name }
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
upsertGroup(group);
|
|
97
|
+
setFetched(true);
|
|
98
|
+
return group;
|
|
99
|
+
} catch (err) {
|
|
100
|
+
error.value = err instanceof Error ? err.message : "Erro ao criar pasta";
|
|
101
|
+
Sentry.captureException(err);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const renameGroup = async (groupId, name) => {
|
|
106
|
+
error.value = null;
|
|
107
|
+
const previousGroups = groups.value;
|
|
108
|
+
const group = groups.value.find((item) => item.id === groupId);
|
|
109
|
+
if (!group)
|
|
110
|
+
return false;
|
|
111
|
+
upsertGroup({ ...group, name, updatedAt: /* @__PURE__ */ new Date() });
|
|
112
|
+
try {
|
|
113
|
+
const updated = await $fetch(
|
|
114
|
+
chatApi.path(`/conversations/groups/${groupId}`),
|
|
115
|
+
chatApi.withChatHeaders({
|
|
116
|
+
method: "PATCH",
|
|
117
|
+
body: { name }
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
upsertGroup(updated);
|
|
121
|
+
return true;
|
|
122
|
+
} catch (err) {
|
|
123
|
+
groups.value = previousGroups;
|
|
124
|
+
error.value = err instanceof Error ? err.message : "Erro ao renomear pasta";
|
|
125
|
+
Sentry.captureException(err);
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const deleteGroup = async (groupId) => {
|
|
130
|
+
error.value = null;
|
|
131
|
+
const previousGroups = groups.value;
|
|
132
|
+
const { clearGroupFromConversations } = useConversations();
|
|
133
|
+
removeGroup(groupId);
|
|
134
|
+
const restoreConversations = clearGroupFromConversations(groupId);
|
|
135
|
+
try {
|
|
136
|
+
await $fetch(
|
|
137
|
+
chatApi.path(`/conversations/groups/${groupId}`),
|
|
138
|
+
chatApi.withChatHeaders({
|
|
139
|
+
method: "DELETE"
|
|
140
|
+
})
|
|
141
|
+
);
|
|
142
|
+
return true;
|
|
143
|
+
} catch (err) {
|
|
144
|
+
groups.value = previousGroups;
|
|
145
|
+
restoreConversations();
|
|
146
|
+
error.value = err instanceof Error ? err.message : "Erro ao excluir pasta";
|
|
147
|
+
Sentry.captureException(err);
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
return {
|
|
152
|
+
groups: readonly(groups),
|
|
153
|
+
loading: readonly(loading),
|
|
154
|
+
error: readonly(error),
|
|
155
|
+
fetchGroups,
|
|
156
|
+
createGroup,
|
|
157
|
+
renameGroup,
|
|
158
|
+
deleteGroup
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { DeepReadonly } from 'vue';
|
|
2
|
+
import type { Conversation } from '../types/chat.js';
|
|
3
|
+
export type ConversationItemOptions = {
|
|
4
|
+
conversation: DeepReadonly<Conversation>;
|
|
5
|
+
active: boolean;
|
|
6
|
+
draggable?: boolean;
|
|
7
|
+
userImage?: string;
|
|
8
|
+
selectConversation?: (id: string) => void | Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
export type ConversationItemEmit = {
|
|
11
|
+
(e: 'delete', id: string): void;
|
|
12
|
+
(e: 'rename', id: string, title: string): void;
|
|
13
|
+
(e: 'duplicate', id: string): void;
|
|
14
|
+
(e: 'export', id: string): void;
|
|
15
|
+
(e: 'dragStart', id: string): void;
|
|
16
|
+
(e: 'dragEnd'): void;
|
|
17
|
+
};
|
|
18
|
+
export declare function useConversationItem(options: ConversationItemOptions, emit: ConversationItemEmit): {
|
|
19
|
+
isRenamingInline: any;
|
|
20
|
+
renameTitle: any;
|
|
21
|
+
renameInputRef: any;
|
|
22
|
+
showDeleteModal: any;
|
|
23
|
+
menuButtonRef: any;
|
|
24
|
+
isMenuOpen: any;
|
|
25
|
+
conversationPath: any;
|
|
26
|
+
displayTitle: any;
|
|
27
|
+
menuItems: ({
|
|
28
|
+
label: string;
|
|
29
|
+
icon: string;
|
|
30
|
+
click: () => void;
|
|
31
|
+
color?: undefined;
|
|
32
|
+
} | {
|
|
33
|
+
label: string;
|
|
34
|
+
icon: string;
|
|
35
|
+
color: "negative";
|
|
36
|
+
click: () => boolean;
|
|
37
|
+
})[];
|
|
38
|
+
confirmDelete: () => void;
|
|
39
|
+
cancelDelete: () => void;
|
|
40
|
+
handleConversationClick: (event: MouseEvent) => void;
|
|
41
|
+
startRename: () => void;
|
|
42
|
+
handleConversationDoubleClick: () => void;
|
|
43
|
+
handleConversationDragStart: (event: DragEvent) => void;
|
|
44
|
+
handleConversationDragEnd: () => void;
|
|
45
|
+
cancelRename: () => void;
|
|
46
|
+
submitRename: () => void;
|
|
47
|
+
handleRenameBlur: () => void;
|
|
48
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { useMagicKeys, useMutationObserver } from "@vueuse/core";
|
|
2
|
+
import { resolveConversationRenameTitle } from "../utils/conversation-title.js";
|
|
3
|
+
import { capitalizeFirst } from "../utils/string.js";
|
|
4
|
+
const conversationNavigationDelayMs = 250;
|
|
5
|
+
export function useConversationItem(options, emit) {
|
|
6
|
+
const isRenamingInline = ref(false);
|
|
7
|
+
const renameTitle = ref("");
|
|
8
|
+
const renameInputRef = ref(null);
|
|
9
|
+
const isIgnoringInitialRenameBlur = ref(false);
|
|
10
|
+
const showDeleteModal = ref(false);
|
|
11
|
+
const menuButtonRef = ref(null);
|
|
12
|
+
const isMenuOpen = ref(false);
|
|
13
|
+
const conversationPath = computed(() => `/${options.conversation.id}`);
|
|
14
|
+
const displayTitle = computed(() => capitalizeFirst(options.conversation.title));
|
|
15
|
+
const { escape } = useMagicKeys();
|
|
16
|
+
let conversationNavigationTimer = null;
|
|
17
|
+
let renameBlurTimer = null;
|
|
18
|
+
watch(() => escape?.value, (pressed) => {
|
|
19
|
+
if (pressed && isRenamingInline.value) {
|
|
20
|
+
cancelRename();
|
|
21
|
+
}
|
|
22
|
+
if (pressed && showDeleteModal.value) {
|
|
23
|
+
cancelDelete();
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
useMutationObserver(menuButtonRef, (mutations) => {
|
|
27
|
+
for (const mutation of mutations) {
|
|
28
|
+
if (mutation.attributeName === "data-state") {
|
|
29
|
+
isMenuOpen.value = menuButtonRef.value?.getAttribute("data-state") === "open";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}, { attributes: true });
|
|
33
|
+
function clearPendingConversationNavigation() {
|
|
34
|
+
if (conversationNavigationTimer === null)
|
|
35
|
+
return;
|
|
36
|
+
clearTimeout(conversationNavigationTimer);
|
|
37
|
+
conversationNavigationTimer = null;
|
|
38
|
+
}
|
|
39
|
+
function clearRenameBlurTimer() {
|
|
40
|
+
if (renameBlurTimer === null)
|
|
41
|
+
return;
|
|
42
|
+
clearTimeout(renameBlurTimer);
|
|
43
|
+
renameBlurTimer = null;
|
|
44
|
+
}
|
|
45
|
+
function allowRenameBlurSoon() {
|
|
46
|
+
clearRenameBlurTimer();
|
|
47
|
+
renameBlurTimer = setTimeout(() => {
|
|
48
|
+
isIgnoringInitialRenameBlur.value = false;
|
|
49
|
+
renameBlurTimer = null;
|
|
50
|
+
}, 100);
|
|
51
|
+
}
|
|
52
|
+
function confirmDelete() {
|
|
53
|
+
showDeleteModal.value = false;
|
|
54
|
+
emit("delete", options.conversation.id);
|
|
55
|
+
}
|
|
56
|
+
function cancelDelete() {
|
|
57
|
+
showDeleteModal.value = false;
|
|
58
|
+
}
|
|
59
|
+
function handleConversationClick(event) {
|
|
60
|
+
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
|
|
61
|
+
return;
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
clearPendingConversationNavigation();
|
|
64
|
+
if (event.detail > 1)
|
|
65
|
+
return;
|
|
66
|
+
conversationNavigationTimer = setTimeout(() => {
|
|
67
|
+
if (options.selectConversation) {
|
|
68
|
+
void options.selectConversation(options.conversation.id);
|
|
69
|
+
} else {
|
|
70
|
+
navigateTo(conversationPath.value);
|
|
71
|
+
}
|
|
72
|
+
conversationNavigationTimer = null;
|
|
73
|
+
}, conversationNavigationDelayMs);
|
|
74
|
+
}
|
|
75
|
+
async function focusRenameInput() {
|
|
76
|
+
await nextTick();
|
|
77
|
+
renameInputRef.value?.focus();
|
|
78
|
+
renameInputRef.value?.select();
|
|
79
|
+
allowRenameBlurSoon();
|
|
80
|
+
}
|
|
81
|
+
function startRename() {
|
|
82
|
+
isMenuOpen.value = false;
|
|
83
|
+
clearPendingConversationNavigation();
|
|
84
|
+
clearRenameBlurTimer();
|
|
85
|
+
renameTitle.value = options.conversation.title;
|
|
86
|
+
isIgnoringInitialRenameBlur.value = true;
|
|
87
|
+
isRenamingInline.value = true;
|
|
88
|
+
void focusRenameInput();
|
|
89
|
+
}
|
|
90
|
+
function handleConversationDoubleClick() {
|
|
91
|
+
clearPendingConversationNavigation();
|
|
92
|
+
startRename();
|
|
93
|
+
}
|
|
94
|
+
function handleConversationDragStart(event) {
|
|
95
|
+
if (!options.draggable)
|
|
96
|
+
return;
|
|
97
|
+
event.dataTransfer?.setData("text/plain", options.conversation.id);
|
|
98
|
+
if (event.dataTransfer) {
|
|
99
|
+
event.dataTransfer.effectAllowed = "move";
|
|
100
|
+
}
|
|
101
|
+
emit("dragStart", options.conversation.id);
|
|
102
|
+
}
|
|
103
|
+
function handleConversationDragEnd() {
|
|
104
|
+
emit("dragEnd");
|
|
105
|
+
}
|
|
106
|
+
function cancelRename() {
|
|
107
|
+
isRenamingInline.value = false;
|
|
108
|
+
isIgnoringInitialRenameBlur.value = false;
|
|
109
|
+
renameTitle.value = "";
|
|
110
|
+
clearRenameBlurTimer();
|
|
111
|
+
}
|
|
112
|
+
function submitRename() {
|
|
113
|
+
if (!isRenamingInline.value)
|
|
114
|
+
return;
|
|
115
|
+
const title = resolveConversationRenameTitle(renameTitle.value, options.conversation.title);
|
|
116
|
+
if (!title) {
|
|
117
|
+
cancelRename();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
emit("rename", options.conversation.id, title);
|
|
121
|
+
cancelRename();
|
|
122
|
+
}
|
|
123
|
+
function handleRenameBlur() {
|
|
124
|
+
if (isIgnoringInitialRenameBlur.value)
|
|
125
|
+
return;
|
|
126
|
+
submitRename();
|
|
127
|
+
}
|
|
128
|
+
const menuItems = [
|
|
129
|
+
{
|
|
130
|
+
label: "Renomear",
|
|
131
|
+
icon: "i-ph-pencil-simple",
|
|
132
|
+
click: () => startRename()
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
label: "Duplicar",
|
|
136
|
+
icon: "i-ph-copy",
|
|
137
|
+
click: () => emit("duplicate", options.conversation.id)
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
label: "Exportar",
|
|
141
|
+
icon: "i-ph-download-simple",
|
|
142
|
+
click: () => emit("export", options.conversation.id)
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
label: "Excluir",
|
|
146
|
+
icon: "i-ph-trash",
|
|
147
|
+
color: "negative",
|
|
148
|
+
click: () => showDeleteModal.value = true
|
|
149
|
+
}
|
|
150
|
+
];
|
|
151
|
+
onBeforeUnmount(() => {
|
|
152
|
+
clearPendingConversationNavigation();
|
|
153
|
+
clearRenameBlurTimer();
|
|
154
|
+
});
|
|
155
|
+
return {
|
|
156
|
+
isRenamingInline,
|
|
157
|
+
renameTitle,
|
|
158
|
+
renameInputRef,
|
|
159
|
+
showDeleteModal,
|
|
160
|
+
menuButtonRef,
|
|
161
|
+
isMenuOpen,
|
|
162
|
+
conversationPath,
|
|
163
|
+
displayTitle,
|
|
164
|
+
menuItems,
|
|
165
|
+
confirmDelete,
|
|
166
|
+
cancelDelete,
|
|
167
|
+
handleConversationClick,
|
|
168
|
+
startRename,
|
|
169
|
+
handleConversationDoubleClick,
|
|
170
|
+
handleConversationDragStart,
|
|
171
|
+
handleConversationDragEnd,
|
|
172
|
+
cancelRename,
|
|
173
|
+
submitRename,
|
|
174
|
+
handleRenameBlur
|
|
175
|
+
};
|
|
176
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { DeepReadonly } from 'vue';
|
|
2
|
+
import type { Conversation } from '../types/chat.js';
|
|
3
|
+
export type ConversationListOptions = {
|
|
4
|
+
conversations: DeepReadonly<Conversation[]>;
|
|
5
|
+
currentId?: string;
|
|
6
|
+
getMemberImage?: (userId: string) => string | undefined;
|
|
7
|
+
selectConversation?: (id: string) => void | Promise<void>;
|
|
8
|
+
resetConversation?: () => void | Promise<void>;
|
|
9
|
+
startConversation?: (groupId?: string | null) => void | Promise<void>;
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export type GroupDeleteTarget = {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
conversationIds: string[];
|
|
16
|
+
conversationCount: number;
|
|
17
|
+
};
|
|
18
|
+
export declare function useConversationList(options: ConversationListOptions): {
|
|
19
|
+
conversationSearch: any;
|
|
20
|
+
groupedConversations: any;
|
|
21
|
+
hasConversationSearchQuery: any;
|
|
22
|
+
hasConversationContent: any;
|
|
23
|
+
shouldShowSkeleton: any;
|
|
24
|
+
emptyConversationMessage: any;
|
|
25
|
+
skeletonRows: readonly [{
|
|
26
|
+
readonly id: "row-1";
|
|
27
|
+
readonly width: "72%";
|
|
28
|
+
}, {
|
|
29
|
+
readonly id: "row-2";
|
|
30
|
+
readonly width: "54%";
|
|
31
|
+
}, {
|
|
32
|
+
readonly id: "row-3";
|
|
33
|
+
readonly width: "64%";
|
|
34
|
+
}, {
|
|
35
|
+
readonly id: "row-4";
|
|
36
|
+
readonly width: "46%";
|
|
37
|
+
}, {
|
|
38
|
+
readonly id: "row-5";
|
|
39
|
+
readonly width: "78%";
|
|
40
|
+
}, {
|
|
41
|
+
readonly id: "row-6";
|
|
42
|
+
readonly width: "58%";
|
|
43
|
+
}, {
|
|
44
|
+
readonly id: "row-7";
|
|
45
|
+
readonly width: "69%";
|
|
46
|
+
}, {
|
|
47
|
+
readonly id: "row-8";
|
|
48
|
+
readonly width: "51%";
|
|
49
|
+
}, {
|
|
50
|
+
readonly id: "row-9";
|
|
51
|
+
readonly width: "74%";
|
|
52
|
+
}, {
|
|
53
|
+
readonly id: "row-10";
|
|
54
|
+
readonly width: "62%";
|
|
55
|
+
}];
|
|
56
|
+
groupItems: any;
|
|
57
|
+
ungroupedConversations: any;
|
|
58
|
+
ungroupedDropTarget: any;
|
|
59
|
+
ungroupedConversationLabel: any;
|
|
60
|
+
shouldShowUngroupedHeader: any;
|
|
61
|
+
showGroupCreationPrompt: any;
|
|
62
|
+
showDeleteGroupModal: any;
|
|
63
|
+
showDeleteGroupConversationsModal: any;
|
|
64
|
+
groupActionLoading: any;
|
|
65
|
+
deleteGroupTarget: any;
|
|
66
|
+
deleteGroupConversationsTarget: any;
|
|
67
|
+
renamingGroupId: any;
|
|
68
|
+
renameGroupName: any;
|
|
69
|
+
renameGroupError: any;
|
|
70
|
+
deleteGroupConfirmationMessage: any;
|
|
71
|
+
deleteGroupConversationsConfirmationMessage: any;
|
|
72
|
+
isGroupOpen: (groupId: string) => any;
|
|
73
|
+
setGroupOpen: (groupId: string, open: boolean) => void;
|
|
74
|
+
toggleGroup: (groupId: string) => void;
|
|
75
|
+
openDeleteGroupModal: (groupId: string, groupName: string, conversations: readonly Pick<Conversation, "id">[]) => void;
|
|
76
|
+
openDeleteGroupConversationsModal: (groupId: string, groupName: string, conversations: readonly Pick<Conversation, "id">[]) => void;
|
|
77
|
+
startRenameGroup: (groupId: string, groupName: string) => void;
|
|
78
|
+
setRenameGroupInputRef: (element: unknown, groupId: string) => void;
|
|
79
|
+
getGroupMenuItems: (groupId: string, groupName: string, conversations: readonly Pick<Conversation, "id">[]) => ({
|
|
80
|
+
label: string;
|
|
81
|
+
icon: string;
|
|
82
|
+
click: () => void;
|
|
83
|
+
color?: undefined;
|
|
84
|
+
disabled?: undefined;
|
|
85
|
+
} | {
|
|
86
|
+
label: string;
|
|
87
|
+
icon: string;
|
|
88
|
+
color: "negative";
|
|
89
|
+
click: () => void;
|
|
90
|
+
disabled?: undefined;
|
|
91
|
+
} | {
|
|
92
|
+
label: string;
|
|
93
|
+
icon: string;
|
|
94
|
+
color: "negative";
|
|
95
|
+
disabled: boolean;
|
|
96
|
+
click: () => void;
|
|
97
|
+
})[];
|
|
98
|
+
clearDeleteGroupTarget: () => void;
|
|
99
|
+
clearDeleteGroupConversationsTarget: () => void;
|
|
100
|
+
cancelRenameGroup: () => void;
|
|
101
|
+
formatConversationCount: (count: number) => string;
|
|
102
|
+
groupConversationsMoveMessage: (count: number) => "A conversa desta pasta será movida para Conversas." | "As conversas desta pasta serão movidas para Conversas.";
|
|
103
|
+
confirmDeleteGroup: () => Promise<void>;
|
|
104
|
+
confirmDeleteGroupConversations: () => Promise<void>;
|
|
105
|
+
submitRenameGroup: () => Promise<void>;
|
|
106
|
+
handleRenameGroupBlur: () => void;
|
|
107
|
+
handleDelete: (id: string) => Promise<void>;
|
|
108
|
+
handleRename: (id: string, title: string) => Promise<void>;
|
|
109
|
+
handleDuplicate: (id: string) => Promise<void>;
|
|
110
|
+
handleExport: (id: string) => Promise<void>;
|
|
111
|
+
handleConversationDragStart: (id: string) => void;
|
|
112
|
+
clearDragState: () => void;
|
|
113
|
+
handleDragEnter: (groupId: string | null) => void;
|
|
114
|
+
handleDragOver: (event: DragEvent, groupId: string | null) => void;
|
|
115
|
+
handleDragLeave: (event: DragEvent, groupId: string | null) => void;
|
|
116
|
+
isDropTarget: (groupId: string | null) => boolean;
|
|
117
|
+
getConversationItemProps: (conversation: DeepReadonly<Conversation>) => {
|
|
118
|
+
conversation: {
|
|
119
|
+
readonly [x: string]: any;
|
|
120
|
+
};
|
|
121
|
+
active: boolean;
|
|
122
|
+
draggable: boolean;
|
|
123
|
+
userImage: string | undefined;
|
|
124
|
+
selectConversation: ((id: string) => void | Promise<void>) | undefined;
|
|
125
|
+
};
|
|
126
|
+
handleConversationDrop: (event: DragEvent, groupId: string | null) => Promise<void>;
|
|
127
|
+
startConversationInGroup: (groupId: string) => void;
|
|
128
|
+
};
|