From d186f0c1900510ce98d6bc3a3aec3b28c106c570 Mon Sep 17 00:00:00 2001 From: Webifi Date: Mon, 17 Jul 2023 14:01:16 -0500 Subject: [PATCH] Import profile on chat context menu. Fix file load bug --- src/lib/ChatOptionMenu.svelte | 46 +++++++++++++++++++++++++++++--- src/lib/ChatSettingsModal.svelte | 1 + src/lib/Util.svelte | 15 ++++++++--- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/lib/ChatOptionMenu.svelte b/src/lib/ChatOptionMenu.svelte index 26f2796..1d40e40 100644 --- a/src/lib/ChatOptionMenu.svelte +++ b/src/lib/ChatOptionMenu.svelte @@ -18,14 +18,15 @@ faEyeSlash } from '@fortawesome/free-solid-svg-icons/index' import { faSquareMinus, faSquarePlus as faSquarePlusOutline } from '@fortawesome/free-regular-svg-icons/index' - import { apiKeyStorage, addChatFromJSON, chatsStorage, checkStateChange, clearChats, clearMessages, copyChat, globalStorage, setGlobalSettingValueByKey, showSetChatSettings, pinMainMenu, getChat, deleteChat, saveChatStore } from './Storage.svelte' + import { apiKeyStorage, addChatFromJSON, chatsStorage, checkStateChange, clearChats, clearMessages, copyChat, globalStorage, setGlobalSettingValueByKey, showSetChatSettings, pinMainMenu, getChat, deleteChat, saveChatStore, saveCustomProfile } from './Storage.svelte' import { exportAsMarkdown, exportChatAsJSON } from './Export.svelte' - import { restartProfile } from './Profiles.svelte' + import { newNameForProfile, restartProfile } from './Profiles.svelte' import { replace } from 'svelte-spa-router' import { clickOutside } from 'svelte-use-click-outside' import { openModal } from 'svelte-modals' import PromptConfirm from './PromptConfirm.svelte' - import { startNewChatWithWarning, startNewChatFromChatId } from './Util.svelte' + import { startNewChatWithWarning, startNewChatFromChatId, errorNotice, encodeHTMLEntities } from './Util.svelte' + import type { ChatSettings } from './Types.svelte' export let chatId export const show = (showHide:boolean = true) => { @@ -37,10 +38,12 @@ let showChatMenu = false let chatFileInput + let profileFileInput const importChatFromFile = (e) => { close() const image = e.target.files[0] + e.target.value = null const reader = new FileReader() reader.readAsText(image) reader.onload = e => { @@ -121,6 +124,38 @@ }) } + const importProfileFromFile = (e) => { + const image = e.target.files[0] + e.target.value = null + const reader = new FileReader() + reader.onload = e => { + const json = (e.target || {}).result as string + try { + const profile = JSON.parse(json) as ChatSettings + profile.profileName = newNameForProfile(profile.profileName || '') + profile.profile = null as any + saveCustomProfile(profile) + openModal(PromptConfirm, { + title: 'Profile Restored', + class: 'is-info', + message: 'Profile restored as:
' + encodeHTMLEntities(profile.profileName) + + '

Start new chat with this profile?', + asHtml: true, + onConfirm: () => { + startNewChatWithWarning(chatId, profile) + }, + onCancel: () => {} + }) + } catch (e) { + errorNotice('Unable to import profile:', e) + } + } + reader.onerror = e => { + errorNotice('Unable to import profile:', new Error('Unknown error')) + } + reader.readAsText(image) + } + importChatFromFile(e)} bind:this={chatFileInput} > + importProfileFromFile(e)} bind:this={profileFileInput} > diff --git a/src/lib/ChatSettingsModal.svelte b/src/lib/ChatSettingsModal.svelte index 99eb213..e41bd67 100644 --- a/src/lib/ChatSettingsModal.svelte +++ b/src/lib/ChatSettingsModal.svelte @@ -147,6 +147,7 @@ const importProfileFromFile = (e) => { const image = e.target.files[0] + e.target.value = null const reader = new FileReader() reader.readAsText(image) reader.onload = e => { diff --git a/src/lib/Util.svelte b/src/lib/Util.svelte index 5c4b9c9..c07c50e 100644 --- a/src/lib/Util.svelte +++ b/src/lib/Util.svelte @@ -5,6 +5,7 @@ import { addChat, getChat } from './Storage.svelte' import { replace } from 'svelte-spa-router' import PromptConfirm from './PromptConfirm.svelte' + import type { ChatSettings } from './Types.svelte' export const sizeTextElements = () => { const els = document.querySelectorAll('textarea.auto-size') for (let i:number = 0, l = els.length; i < l; i++) autoGrowInput(els[i] as HTMLTextAreaElement) @@ -95,6 +96,10 @@ } } + export const encodeHTMLEntities = (rawStr:string) => { + return rawStr.replace(/[\u00A0-\u9999<>&]/g, (i) => `&#${i.charCodeAt(0)};`) + } + export const errorNotice = (message:string, error:Error|undefined = undefined):any => { openModal(PromptNotice, { title: 'Error', @@ -121,7 +126,11 @@ replace(`/chat/${newChatId}`) } - export const startNewChatWithWarning = (activeChatId: number|undefined) => { + export const startNewChatWithWarning = (activeChatId: number|undefined, profile?: ChatSettings|undefined) => { + const newChat = () => { + const chatId = addChat(profile) + replace(`/chat/${chatId}`) + } if (activeChatId && getChat(activeChatId).settings.isDirty) { openModal(PromptConfirm, { title: 'Unsaved Profile', @@ -129,11 +138,11 @@ asHtml: true, class: 'is-warning', onConfirm: () => { - replace('#/chat/new') + newChat() } }) } else { - replace('#/chat/new') + newChat() } }