@meistrari/chat-nuxt 1.1.3 → 1.2.1
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 +70 -4
- package/dist/module.d.mts +5 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +74 -27
- package/dist/runtime/components/chat/conversation-list.d.vue.ts +1 -0
- package/dist/runtime/components/chat/conversation-list.vue +22 -2
- package/dist/runtime/components/chat/conversation-list.vue.d.ts +1 -0
- package/dist/runtime/components/chat/message-list.d.vue.ts +1 -0
- package/dist/runtime/components/chat/message-list.vue +23 -2
- package/dist/runtime/components/chat/message-list.vue.d.ts +1 -0
- package/dist/runtime/composables/useChat.d.ts +2 -1
- package/dist/runtime/composables/useChat.js +32 -3
- package/dist/runtime/composables/useChatApi.js +2 -1
- package/dist/runtime/composables/useConversations.d.ts +6 -3
- package/dist/runtime/composables/useConversations.js +114 -12
- package/dist/runtime/composables/useEmbedConfig.d.ts +11 -6
- package/dist/runtime/composables/useEmbedConfig.js +35 -7
- package/dist/runtime/composables/useIDB.js +4 -0
- package/dist/runtime/composables/usePdf.d.ts +840 -1
- package/dist/runtime/composables/usePdf.js +21 -3
- package/dist/runtime/composables/useWorkspaceContextFiles.d.ts +3 -3
- package/dist/runtime/composables/useWorkspaceContextFiles.js +19 -10
- package/dist/runtime/composables/useWorkspaceExternalSkills.d.ts +1 -1
- package/dist/runtime/composables/useWorkspaceExternalSkills.js +5 -6
- package/dist/runtime/composables/useWorkspacePersonalization.d.ts +1 -1
- package/dist/runtime/composables/useWorkspacePersonalization.js +4 -5
- package/dist/runtime/composables/useWorkspaceSettings.js +11 -12
- package/dist/runtime/embed/components/ChatConfigurationModal.d.vue.ts +25 -0
- package/dist/runtime/embed/components/ChatConfigurationModal.vue +373 -0
- package/dist/runtime/embed/components/ChatConfigurationModal.vue.d.ts +25 -0
- package/dist/runtime/embed/components/ChatEmbed.vue +12 -1
- package/dist/runtime/embed/components/ChatEmbedInner.vue +35 -19
- package/dist/runtime/embed/components/configuration/ChatConfigurationContextFilesTab.d.vue.ts +22 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationContextFilesTab.vue +133 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationContextFilesTab.vue.d.ts +22 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationCredentialsTab.d.vue.ts +10 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationCredentialsTab.vue +220 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationCredentialsTab.vue.d.ts +10 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationExternalSkillsTab.d.vue.ts +32 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationExternalSkillsTab.vue +222 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationExternalSkillsTab.vue.d.ts +32 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationKnowledgeSourcesTab.d.vue.ts +18 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationKnowledgeSourcesTab.vue +142 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationKnowledgeSourcesTab.vue.d.ts +18 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationPersonalizationTab.d.vue.ts +10 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationPersonalizationTab.vue +37 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationPersonalizationTab.vue.d.ts +10 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationTelaToolsTab.d.vue.ts +20 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationTelaToolsTab.vue +146 -0
- package/dist/runtime/embed/components/configuration/ChatConfigurationTelaToolsTab.vue.d.ts +20 -0
- package/dist/runtime/server/api/conversations/[id]/duplicate.post.js +45 -12
- package/dist/runtime/types/chat.d.ts +2 -1
- package/dist/runtime/types/workspace-settings.d.ts +3 -0
- package/dist/runtime/types/workspace-settings.js +0 -0
- package/dist/runtime/utils/conversation-list-skeleton.d.ts +31 -0
- package/dist/runtime/utils/conversation-list-skeleton.js +12 -0
- package/dist/runtime/utils/file.js +42 -42
- package/dist/types.d.mts +2 -0
- package/package.json +23 -27
- package/dist/runtime/composables/PageNavigation.d.ts +0 -13
- package/dist/runtime/composables/PageNavigation.js +0 -18
- /package/dist/runtime/components/{pdf-preview.d.vue.ts → pdf-preview.client.d.vue.ts} +0 -0
- /package/dist/runtime/components/{pdf-preview.vue → pdf-preview.client.vue} +0 -0
- /package/dist/runtime/components/{pdf-preview.vue.d.ts → pdf-preview.client.vue.d.ts} +0 -0
- /package/dist/runtime/components/{pdf-viewer.d.vue.ts → pdf-viewer.client.d.vue.ts} +0 -0
- /package/dist/runtime/components/{pdf-viewer.vue → pdf-viewer.client.vue} +0 -0
- /package/dist/runtime/components/{pdf-viewer.vue.d.ts → pdf-viewer.client.vue.d.ts} +0 -0
- /package/dist/runtime/public/{github.svg → assets/github.svg} +0 -0
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import * as Sentry from "@sentry/nuxt";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { markRaw, onUnmounted, reactive, watch } from "vue";
|
|
3
|
+
let pdfjsLibPromise = null;
|
|
4
|
+
async function loadPdfjs() {
|
|
5
|
+
if (!import.meta.client)
|
|
6
|
+
return null;
|
|
7
|
+
if (!pdfjsLibPromise) {
|
|
8
|
+
pdfjsLibPromise = import("pdfjs-dist").then((lib) => {
|
|
9
|
+
lib.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${lib.version}/build/pdf.worker.min.mjs`;
|
|
10
|
+
return lib;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
return pdfjsLibPromise;
|
|
14
|
+
}
|
|
5
15
|
export function usePdf(url) {
|
|
6
16
|
const state = reactive({
|
|
7
17
|
pdfDoc: null,
|
|
@@ -13,6 +23,11 @@ export function usePdf(url) {
|
|
|
13
23
|
async function loadPdf() {
|
|
14
24
|
if (isUnmounted)
|
|
15
25
|
return null;
|
|
26
|
+
const pdfjsLib = await loadPdfjs();
|
|
27
|
+
if (!pdfjsLib) {
|
|
28
|
+
state.isLoading = false;
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
16
31
|
state.isLoading = true;
|
|
17
32
|
state.loadError = null;
|
|
18
33
|
try {
|
|
@@ -68,6 +83,9 @@ export function usePdf(url) {
|
|
|
68
83
|
async function renderTextLayer(page, viewport, textLayer, highlight, highlightPage, pageNum) {
|
|
69
84
|
if (isUnmounted)
|
|
70
85
|
return;
|
|
86
|
+
const pdfjsLib = await loadPdfjs();
|
|
87
|
+
if (!pdfjsLib)
|
|
88
|
+
return;
|
|
71
89
|
textLayer.innerHTML = "";
|
|
72
90
|
textLayer.style.width = `${viewport.width}px`;
|
|
73
91
|
textLayer.style.height = `${viewport.height}px`;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { ContextFile } from '../server/db/schema.js';
|
|
2
|
-
import type { WorkspaceSettings, WorkspaceSettingsUpdate } from './useWorkspaceSettings.js';
|
|
3
2
|
export declare const MAX_FILES = 10;
|
|
4
3
|
export declare const MAX_FILE_SIZE: number;
|
|
5
|
-
export declare function useWorkspaceContextFiles(searchQuery: Ref<string>, currentContextFiles: Ref<readonly ContextFile[] | null | undefined> | ComputedRef<readonly ContextFile[] | null | undefined
|
|
4
|
+
export declare function useWorkspaceContextFiles(searchQuery: Ref<string>, currentContextFiles: Ref<readonly ContextFile[] | null | undefined> | ComputedRef<readonly ContextFile[] | null | undefined>): {
|
|
6
5
|
pendingFiles: any;
|
|
7
6
|
filteredContextFiles: any;
|
|
8
7
|
filteredPendingFiles: any;
|
|
@@ -11,9 +10,10 @@ export declare function useWorkspaceContextFiles(searchQuery: Ref<string>, curre
|
|
|
11
10
|
maxFiles: number;
|
|
12
11
|
handleFileSelect: (event: Event) => void;
|
|
13
12
|
removePendingFile: (file: File) => void;
|
|
14
|
-
removeContextFile: (url: string) =>
|
|
13
|
+
removeContextFile: (url: string) => void;
|
|
15
14
|
getFileType: (fileName: string) => string;
|
|
16
15
|
initialize: () => void;
|
|
17
16
|
getPendingFiles: () => File[];
|
|
17
|
+
getKeptContextFiles: () => ContextFile[];
|
|
18
18
|
clearPendingFiles: () => void;
|
|
19
19
|
};
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
export const MAX_FILES = 10;
|
|
2
2
|
export const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
3
|
-
export function useWorkspaceContextFiles(searchQuery, currentContextFiles
|
|
3
|
+
export function useWorkspaceContextFiles(searchQuery, currentContextFiles) {
|
|
4
4
|
const pendingFiles = ref([]);
|
|
5
|
+
const removedUrls = ref(/* @__PURE__ */ new Set());
|
|
6
|
+
const effectiveContextFiles = computed(
|
|
7
|
+
() => (currentContextFiles.value ?? []).filter((file) => !removedUrls.value.has(file.url))
|
|
8
|
+
);
|
|
5
9
|
const filteredContextFiles = computed(() => {
|
|
6
|
-
if (!currentContextFiles.value)
|
|
7
|
-
return [];
|
|
8
10
|
if (!searchQuery.value.trim())
|
|
9
|
-
return
|
|
11
|
+
return effectiveContextFiles.value;
|
|
10
12
|
const query = searchQuery.value.toLowerCase();
|
|
11
|
-
return
|
|
13
|
+
return effectiveContextFiles.value.filter(
|
|
12
14
|
(file) => file.name.toLowerCase().includes(query)
|
|
13
15
|
);
|
|
14
16
|
});
|
|
@@ -21,10 +23,10 @@ export function useWorkspaceContextFiles(searchQuery, currentContextFiles, updat
|
|
|
21
23
|
);
|
|
22
24
|
});
|
|
23
25
|
const currentFileCount = computed(
|
|
24
|
-
() =>
|
|
26
|
+
() => effectiveContextFiles.value.length + pendingFiles.value.length
|
|
25
27
|
);
|
|
26
28
|
const hasChanges = computed(
|
|
27
|
-
() => pendingFiles.value.length > 0
|
|
29
|
+
() => pendingFiles.value.length > 0 || removedUrls.value.size > 0
|
|
28
30
|
);
|
|
29
31
|
function handleFileSelect(event) {
|
|
30
32
|
const target = event.target;
|
|
@@ -40,21 +42,27 @@ export function useWorkspaceContextFiles(searchQuery, currentContextFiles, updat
|
|
|
40
42
|
if (idx !== -1)
|
|
41
43
|
pendingFiles.value = pendingFiles.value.filter((_, i) => i !== idx);
|
|
42
44
|
}
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
45
|
+
function removeContextFile(url) {
|
|
46
|
+
const next = new Set(removedUrls.value);
|
|
47
|
+
next.add(url);
|
|
48
|
+
removedUrls.value = next;
|
|
46
49
|
}
|
|
47
50
|
function getFileType(fileName) {
|
|
48
51
|
return fileName.split(".").pop()?.toUpperCase() ?? "";
|
|
49
52
|
}
|
|
50
53
|
function initialize() {
|
|
51
54
|
pendingFiles.value = [];
|
|
55
|
+
removedUrls.value = /* @__PURE__ */ new Set();
|
|
52
56
|
}
|
|
53
57
|
function getPendingFiles() {
|
|
54
58
|
return [...pendingFiles.value];
|
|
55
59
|
}
|
|
60
|
+
function getKeptContextFiles() {
|
|
61
|
+
return [...effectiveContextFiles.value];
|
|
62
|
+
}
|
|
56
63
|
function clearPendingFiles() {
|
|
57
64
|
pendingFiles.value = [];
|
|
65
|
+
removedUrls.value = /* @__PURE__ */ new Set();
|
|
58
66
|
}
|
|
59
67
|
return {
|
|
60
68
|
pendingFiles: readonly(pendingFiles),
|
|
@@ -69,6 +77,7 @@ export function useWorkspaceContextFiles(searchQuery, currentContextFiles, updat
|
|
|
69
77
|
getFileType,
|
|
70
78
|
initialize,
|
|
71
79
|
getPendingFiles,
|
|
80
|
+
getKeptContextFiles,
|
|
72
81
|
clearPendingFiles
|
|
73
82
|
};
|
|
74
83
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExternalSkill } from '../server/db/schema.js';
|
|
2
|
-
export declare function useWorkspaceExternalSkills(searchQuery?: Ref<string>): {
|
|
2
|
+
export declare function useWorkspaceExternalSkills(currentExternalSkills: Ref<readonly ExternalSkill[] | null | undefined> | ComputedRef<readonly ExternalSkill[] | null | undefined>, searchQuery?: Ref<string>): {
|
|
3
3
|
displayedSkills: any;
|
|
4
4
|
filteredSkills: any;
|
|
5
5
|
hasChanges: any;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
export function useWorkspaceExternalSkills(searchQuery) {
|
|
2
|
-
const { settings } = useWorkspaceSettings();
|
|
1
|
+
export function useWorkspaceExternalSkills(currentExternalSkills, searchQuery) {
|
|
3
2
|
const { user } = useTelaApplicationAuth();
|
|
4
3
|
const { connection: skillsConnection, fetchConnection: fetchGitHubConnection, connect: connectGitHub } = useGitHubSkills();
|
|
5
|
-
const pendingSkills =
|
|
6
|
-
const removedRefs =
|
|
4
|
+
const pendingSkills = ref([]);
|
|
5
|
+
const removedRefs = ref([]);
|
|
7
6
|
const skillModalOpen = ref(false);
|
|
8
7
|
const skillRefInput = ref("");
|
|
9
8
|
const skillError = ref("");
|
|
10
9
|
const discoveringSkills = ref(false);
|
|
11
10
|
const displayedSkills = computed(() => {
|
|
12
|
-
const current = (
|
|
11
|
+
const current = (currentExternalSkills.value ?? []).filter((s) => !removedRefs.value.includes(s.ref));
|
|
13
12
|
return [...current, ...pendingSkills.value];
|
|
14
13
|
});
|
|
15
14
|
const filteredSkills = computed(() => {
|
|
@@ -38,7 +37,7 @@ export function useWorkspaceExternalSkills(searchQuery) {
|
|
|
38
37
|
removedRefs.value = [...removedRefs.value, ref2];
|
|
39
38
|
}
|
|
40
39
|
function buildExternalSkills() {
|
|
41
|
-
const currentSkills = (
|
|
40
|
+
const currentSkills = (currentExternalSkills.value ?? []).filter((s) => !removedRefs.value.includes(s.ref)).map((s) => ({
|
|
42
41
|
...s,
|
|
43
42
|
allowedTools: [...s.allowedTools],
|
|
44
43
|
addedBy: { ...s.addedBy }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function useWorkspacePersonalization(): {
|
|
1
|
+
export declare function useWorkspacePersonalization(currentSystemMessage: Ref<string | null | undefined> | ComputedRef<string | null | undefined>): {
|
|
2
2
|
localSystemMessage: any;
|
|
3
3
|
hasChanges: any;
|
|
4
4
|
getSystemMessage: () => string | null;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
export function useWorkspacePersonalization() {
|
|
2
|
-
const
|
|
3
|
-
const localSystemMessage = useState("workspace-personalization-system-message", () => "");
|
|
1
|
+
export function useWorkspacePersonalization(currentSystemMessage) {
|
|
2
|
+
const localSystemMessage = ref("");
|
|
4
3
|
const hasChanges = computed(
|
|
5
|
-
() => localSystemMessage.value !== (
|
|
4
|
+
() => localSystemMessage.value !== (currentSystemMessage.value ?? "")
|
|
6
5
|
);
|
|
7
6
|
function getSystemMessage() {
|
|
8
7
|
return localSystemMessage.value.trim() || null;
|
|
9
8
|
}
|
|
10
9
|
function initialize() {
|
|
11
|
-
localSystemMessage.value =
|
|
10
|
+
localSystemMessage.value = currentSystemMessage.value ?? "";
|
|
12
11
|
}
|
|
13
12
|
return {
|
|
14
13
|
localSystemMessage,
|
|
@@ -2,7 +2,8 @@ import * as Sentry from "@sentry/nuxt";
|
|
|
2
2
|
export function useWorkspaceSettings() {
|
|
3
3
|
const chatApi = useChatApi();
|
|
4
4
|
const embedConfig = useEmbedConfig();
|
|
5
|
-
const
|
|
5
|
+
const { activeOrganization } = useTelaApplicationAuth();
|
|
6
|
+
const workspaceScope = computed(() => embedConfig?.workspaceId.value.trim() || activeOrganization.value?.id?.trim() || "default");
|
|
6
7
|
const settingsBuckets = useState("workspace-settings", () => ({}));
|
|
7
8
|
const loadingBuckets = useState("workspace-settings-loading", () => ({}));
|
|
8
9
|
const errorBuckets = useState("workspace-settings-error", () => ({}));
|
|
@@ -35,7 +36,8 @@ export function useWorkspaceSettings() {
|
|
|
35
36
|
});
|
|
36
37
|
const isModalOpen = useState("workspace-settings-modal-open", () => false);
|
|
37
38
|
const initialTab = useState("workspace-settings-initial-tab", () => null);
|
|
38
|
-
|
|
39
|
+
const hasWorkspaceSettingsOverride = computed(() => embedConfig?.workspaceSettings.value !== void 0);
|
|
40
|
+
if (embedConfig !== null && hasWorkspaceSettingsOverride.value) {
|
|
39
41
|
settings.value = embedConfig.workspaceSettings.value;
|
|
40
42
|
}
|
|
41
43
|
if (embedConfig !== null) {
|
|
@@ -46,15 +48,11 @@ export function useWorkspaceSettings() {
|
|
|
46
48
|
});
|
|
47
49
|
}
|
|
48
50
|
function openModal(tab) {
|
|
49
|
-
if (embedConfig !== null)
|
|
50
|
-
return;
|
|
51
51
|
if (tab)
|
|
52
52
|
initialTab.value = tab;
|
|
53
53
|
isModalOpen.value = true;
|
|
54
54
|
}
|
|
55
55
|
function closeModal() {
|
|
56
|
-
if (embedConfig !== null)
|
|
57
|
-
return;
|
|
58
56
|
isModalOpen.value = false;
|
|
59
57
|
initialTab.value = null;
|
|
60
58
|
}
|
|
@@ -64,7 +62,9 @@ export function useWorkspaceSettings() {
|
|
|
64
62
|
try {
|
|
65
63
|
const currentSettings = settings.value;
|
|
66
64
|
let data;
|
|
67
|
-
if (
|
|
65
|
+
if (hasWorkspaceSettingsOverride.value) {
|
|
66
|
+
return settings.value;
|
|
67
|
+
} else if (embedConfig !== null) {
|
|
68
68
|
data = await $fetch(
|
|
69
69
|
chatApi.path("/workspace/settings"),
|
|
70
70
|
chatApi.withChatHeaders()
|
|
@@ -102,15 +102,14 @@ export function useWorkspaceSettings() {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
async function updateSettings(updates) {
|
|
105
|
-
if (
|
|
105
|
+
if (hasWorkspaceSettingsOverride.value)
|
|
106
106
|
return settings.value;
|
|
107
107
|
loading.value = true;
|
|
108
108
|
error.value = null;
|
|
109
109
|
try {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
});
|
|
110
|
+
const path = embedConfig !== null ? chatApi.path("/workspace/settings") : "/api/workspace/settings";
|
|
111
|
+
const options = embedConfig !== null ? chatApi.withChatHeaders({ method: "PATCH", body: updates }) : { method: "PATCH", body: updates };
|
|
112
|
+
const data = await $fetch(path, options);
|
|
114
113
|
settings.value = data;
|
|
115
114
|
return data;
|
|
116
115
|
} catch (e) {
|
|
@@ -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;
|
|
@@ -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>
|