Highlight just imported chats in the list
| @@ -7360,8 +7360,9 @@ export function getCurrentChatDetails() { | ||
| 7360 | 7360 | * The function first fetches the chats, processes them, and then displays them in |
| 7361 | 7361 | * the HTML. It also has a built-in search functionality that allows filtering the |
| 7362 | 7362 | * displayed chats based on a search query. |
| 7363 | + * @param {string[]} hightlightNames - An array of chat names to highlight | |
| 7363 | 7364 | */ |
| 7364 | 7365 | export async function displayPastChats(hightlightNames = []) { |
| 7365 | 7366 | $('#select_chat_div').empty(); |
| 7366 | 7367 | $('#select_chat_search').val('').off('input'); |
| 7367 | 7368 | |
| @@ -7370,10 +7371,10 @@ export async function displayPastChats() { | ||
| 7370 | 7371 | const displayName = chatDetails.characterName; |
| 7371 | 7372 | const avatarImg = chatDetails.avatarImgURL; |
| 7372 | 7373 | |
| 7373 | 7374 | await displayChats('', currentChat, displayName, avatarImg, selected_group, hightlightNames); |
| 7374 | 7375 | |
| 7375 | 7376 | const debouncedDisplay = debounce((searchQuery) => { |
| 7376 | 7377 | displayChats(searchQuery, currentChat, displayName, avatarImg, selected_group, []); |
| 7377 | 7378 | }); |
| 7378 | 7379 | |
| 7379 | 7380 | // Define the search input listener |
| @@ -7389,7 +7390,7 @@ export async function displayPastChats() { | ||
| 7389 | 7390 | }, 200); |
| 7390 | 7391 | } |
| 7391 | 7392 | |
| 7392 | 7393 | async function displayChats(searchQuery, currentChat, displayName, avatarImg, selected_group, highlightNames) { |
| 7393 | 7394 | try { |
| 7394 | 7395 | const trimExtension = (fileName) => String(fileName).replace('.jsonl', ''); |
| 7395 | 7396 | |
| @@ -7429,6 +7430,12 @@ async function displayChats(searchQuery, currentChat, displayName, avatarImg, se | ||
| 7429 | 7430 | } |
| 7430 | 7431 | |
| 7431 | 7432 | $('#select_chat_div').append(template); |
| 7433 | + | |
| 7434 | + if (Array.isArray(highlightNames) && highlightNames.includes(chat.file_name)) { | |
| 7435 | + const templateOffset = template.offset().top - template.parent().offset().top; | |
| 7436 | + $('#select_chat_div').scrollTop(templateOffset); | |
| 7437 | + flashHighlight(template, debounce_timeout.extended); | |
| 7438 | + } | |
| 7432 | 7439 | } |
| 7433 | 7440 | } catch (error) { |
| 7434 | 7441 | console.error('Error loading chats:', error); |
| @@ -8053,6 +8060,7 @@ export async function saveChatConditional() { | ||
| 8053 | 8060 | * @param {FormData} formData Form data to send to the server. |
| 8054 | 8061 | * @param {object} [options={}] Options for the import |
| 8055 | 8062 | * @param {boolean} [options.refresh] Whether to refresh the group chat list after import |
| 8063 | + * @returns {Promise<string[]>} List of imported file names. | |
| 8056 | 8064 | */ |
| 8057 | 8065 | async function importCharacterChat(formData, { refresh = true } = {}) { |
| 8058 | 8066 | const fetchResult = await fetch('/api/chats/import', { |
| @@ -8067,7 +8075,10 @@ async function importCharacterChat(formData, { refresh = true } = {}) { | ||
| 8067 | 8075 | if (data.res && refresh) { |
| 8068 | 8076 | await displayPastChats(); |
| 8069 | 8077 | } |
| 8078 | + return data?.fileNames || []; | |
| 8070 | 8079 | } |
| 8080 | + | |
| 8081 | + return []; | |
| 8071 | 8082 | } |
| 8072 | 8083 | |
| 8073 | 8084 | function updateViewMessageIds(startFromZero = false) { |
| @@ -10616,6 +10627,8 @@ jQuery(async function () { | ||
| 10616 | 10627 | return; |
| 10617 | 10628 | } |
| 10618 | 10629 | |
| 10630 | + const importedFileNames = []; | |
| 10631 | + | |
| 10619 | 10632 | for (const file of targetElement.files) { |
| 10620 | 10633 | const ext = file.name.match(/\.(\w+)$/); |
| 10621 | 10634 | const format = ext?.[1]?.toLowerCase(); |
| @@ -10636,10 +10649,15 @@ jQuery(async function () { | ||
| 10636 | 10649 | formData.set('user_name', name1); |
| 10637 | 10650 | |
| 10638 | 10651 | const importFn = selected_group ? importGroupChat : importCharacterChat; |
| 10639 | 10652 | const result = await importFn(formData, { refresh: false }); |
| 10653 | + importedFileNames.push(...result); | |
| 10640 | 10654 | } |
| 10641 | 10655 | |
| 10642 | - await displayPastChats(); | |
| 10656 | + if (importedFileNames.length > 0) { | |
| 10657 | + toastr.success(t`Successfully imported ${importedFileNames.length} chat(s).`); | |
| 10658 | + } | |
| 10659 | + | |
| 10660 | + await displayPastChats(importedFileNames); | |
| 10643 | 10661 | |
| 10644 | 10662 | targetElement.value = ''; |
| 10645 | 10663 | }); |
| @@ -2066,6 +2066,7 @@ export async function deleteGroupChat(groupId, chatId, { jumpToNewChat = true } | ||
| 2066 | 2066 | * @param {FormData} formData Form data to send to the server |
| 2067 | 2067 | * @param {object} [options={}] Options for the import |
| 2068 | 2068 | * @param {boolean} [options.refresh] Whether to refresh the group chat list after import |
| 2069 | + * @returns {Promise<string[]>} List of imported file names | |
| 2069 | 2070 | */ |
| 2070 | 2071 | export async function importGroupChat(formData, { refresh = true } = {}) { |
| 2071 | 2072 | const fetchResult = await fetch('/api/chats/group/import', { |
| @@ -2089,7 +2090,11 @@ export async function importGroupChat(formData, { refresh = true } = {}) { | ||
| 2089 | 2090 | } |
| 2090 | 2091 | } |
| 2091 | 2092 | } |
| 2093 | + | |
| 2094 | + return data?.fileNames || []; | |
| 2092 | 2095 | } |
| 2096 | + | |
| 2097 | + return []; | |
| 2093 | 2098 | } |
| 2094 | 2099 | |
| 2095 | 2100 | export async function saveGroupBookmarkChat(groupId, name, metadata, mesId) { |
| @@ -628,6 +628,7 @@ router.post('/import', validateAvatarUrlMiddleware, function (request, response) | ||
| 628 | 628 | const avatarUrl = (request.body.avatar_url).replace('.png', ''); |
| 629 | 629 | const characterName = request.body.character_name; |
| 630 | 630 | const userName = request.body.user_name || 'User'; |
| 631 | + const fileNames = []; | |
| 631 | 632 | |
| 632 | 633 | if (!request.file) { |
| 633 | 634 | return response.sendStatus(400); |
| @@ -662,6 +663,7 @@ router.post('/import', validateAvatarUrlMiddleware, function (request, response) | ||
| 662 | 663 | const handleChat = (chat) => { |
| 663 | 664 | const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`; |
| 664 | 665 | const filePath = path.join(request.user.directories.chats, avatarUrl, fileName); |
| 666 | + fileNames.push(fileName); | |
| 665 | 667 | writeFileAtomicSync(filePath, chat, 'utf8'); |
| 666 | 668 | }; |
| 667 | 669 | |
| @@ -673,7 +675,7 @@ router.post('/import', validateAvatarUrlMiddleware, function (request, response) | ||
| 673 | 675 | handleChat(chat); |
| 674 | 676 | } |
| 675 | 677 | |
| 676 | 678 | return response.send({ res: true, fileNames }); |
| 677 | 679 | } |
| 678 | 680 | |
| 679 | 681 | if (format === 'jsonl') { |
| @@ -700,13 +702,14 @@ router.post('/import', validateAvatarUrlMiddleware, function (request, response) | ||
| 700 | 702 | |
| 701 | 703 | const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`; |
| 702 | 704 | const filePath = path.join(request.user.directories.chats, avatarUrl, fileName); |
| 705 | + fileNames.push(fileName); | |
| 703 | 706 | if (flattenedChat !== data) { |
| 704 | 707 | writeFileAtomicSync(filePath, flattenedChat, 'utf8'); |
| 705 | 708 | } else { |
| 706 | 709 | fs.copyFileSync(pathToUpload, filePath); |
| 707 | 710 | } |
| 708 | 711 | fs.unlinkSync(pathToUpload); |
| 709 | 712 | response.send({ res: true, fileNames }); |
| 710 | 713 | } |
| 711 | 714 | } catch (error) { |
| 712 | 715 | console.error(error); |