diff --git a/src/lib/ChatOptionMenu.svelte b/src/lib/ChatOptionMenu.svelte index 39b1540..2e3bbbf 100644 --- a/src/lib/ChatOptionMenu.svelte +++ b/src/lib/ChatOptionMenu.svelte @@ -17,11 +17,13 @@ faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons/index' - import { apiKeyStorage, addChatFromJSON, chatsStorage, checkStateChange, clearChats, clearMessages, copyChat, globalStorage, setGlobalSettingValueByKey, showSetChatSettings, pinMainMenu } from './Storage.svelte' + import { apiKeyStorage, addChatFromJSON, chatsStorage, checkStateChange, clearChats, clearMessages, copyChat, globalStorage, setGlobalSettingValueByKey, showSetChatSettings, pinMainMenu, getChat, deleteChat } from './Storage.svelte' import { exportAsMarkdown, exportChatAsJSON } from './Export.svelte' import { 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' export let chatId export const show = (showHide:boolean = true) => { @@ -29,6 +31,8 @@ } export let style: string = 'is-right' + $: sortedChats = $chatsStorage.sort((a, b) => b.id - a.id) + let showChatMenu = false let chatFileInput @@ -43,20 +47,45 @@ } } - const deleteChat = () => { + const delChat = () => { close() - if (window.confirm('Are you sure you want to delete this chat?')) { - replace('/').then(() => { - chatsStorage.update((chats) => chats.filter((chat) => chat.id !== chatId)) - }) - } + openModal(PromptConfirm, { + title: 'Delete Chat', + message: 'Are you sure you want to delete this chat?', + class: 'is-warning', + confirmButtonClass: 'is-warning', + confirmButton: 'Delete Chat', + onConfirm: () => { + const thisChat = getChat(chatId) + const thisIndex = sortedChats.indexOf(thisChat) + const prevChat = sortedChats[thisIndex - 1] + const nextChat = sortedChats[thisIndex + 1] + const newChat = nextChat || prevChat + if (!newChat) { + // No other chats, clear all and go to home + replace('/').then(() => { deleteChat(chatId) }) + } else { + // Delete the current chat and go to the max chatId + replace(`/chat/${newChat.id}`).then(() => { deleteChat(chatId) }) + } + }, + onCancel: () => {} + }) } const confirmClearChats = () => { close() - if (window.confirm('Are you sure you want to delete ALL of your chats?')) { - clearChats() - } + openModal(PromptConfirm, { + title: 'Delete ALL Chat', + message: 'Are you sure you want to delete ALL of your chats?', + class: 'is-danger', + confirmButtonClass: 'is-danger', + confirmButton: 'Delete ALL', + onConfirm: () => { + clearChats() + }, + onCancel: () => {} + }) } const close = () => { @@ -116,7 +145,7 @@ Export Chat Markdown - { if (chatId) close(); deleteChat() }}> + { if (chatId) close(); delChat() }}> Delete Chat { if (chatId) confirmClearChats() }}> diff --git a/src/lib/ChatSettingField.svelte b/src/lib/ChatSettingField.svelte index 2c4b6a4..2db714e 100644 --- a/src/lib/ChatSettingField.svelte +++ b/src/lib/ChatSettingField.svelte @@ -3,11 +3,12 @@ // import { getProfile } from './Profiles.svelte' import { cleanSettingValue, setChatSettingValue } from './Storage.svelte' import type { Chat, ChatSetting, ChatSettings, ControlAction, FieldControl, SettingPrompt } from './Types.svelte' - import { autoGrowInputOnEvent } from './Util.svelte' + import { autoGrowInputOnEvent, errorNotice } from './Util.svelte' // import { replace } from 'svelte-spa-router' import Fa from 'svelte-fa/src/fa.svelte' import { openModal } from 'svelte-modals' import PromptConfirm from './PromptConfirm.svelte' + import PromptNotice from './PromptNotice.svelte' export let setting:ChatSetting export let chatSettings:ChatSettings @@ -87,7 +88,7 @@ (typeof setting.beforeChange === 'function') && setting.beforeChange(chatId, setting, el.checked || el.value) && refreshSettings() } catch (e) { - window.alert('Unable to change:\n' + e.message) + openModal(PromptNotice, errorNotice('Unable to change:', e)) } switch (setting.type) { case 'boolean': @@ -106,7 +107,7 @@ } } catch (e) { setChatSettingValue(chatId, setting, val) - window.alert('Unable to change:\n' + e.message) + openModal(PromptNotice, errorNotice('Unable to change:', e)) } dispatch('change', setting) } diff --git a/src/lib/ChatSettingsModal.svelte b/src/lib/ChatSettingsModal.svelte index a4d17bc..ebaa53f 100644 --- a/src/lib/ChatSettingsModal.svelte +++ b/src/lib/ChatSettingsModal.svelte @@ -16,7 +16,7 @@ } from './Storage.svelte' import { supportedModels, type Chat, type ChatSetting, type ResponseModels, type SettingSelect, type SelectOption, type ChatSettings } from './Types.svelte' - import { sizeTextElements } from './Util.svelte' + import { errorNotice, sizeTextElements } from './Util.svelte' import Fa from 'svelte-fa/src/fa.svelte' import { faTrash, @@ -33,6 +33,8 @@ import ChatSettingField from './ChatSettingField.svelte' import { getModelMaxTokens } from './Stats.svelte' import { replace } from 'svelte-spa-router' + import { openModal } from 'svelte-modals' + import PromptNotice from './PromptNotice.svelte' export let chatId:number export const show = () => { showSettings() } @@ -101,7 +103,7 @@ applyProfile(chatId, clone.profile) refreshSettings() } catch (e) { - window.alert('Error cloning profile: \n' + e.message) + openModal(PromptNotice, errorNotice('Error cloning profile:', e)) } } @@ -115,7 +117,7 @@ applyProfile(chatId, chat.settings.profile as any) refreshSettings() } catch (e) { - window.alert('Error deleting profile: \n' + e.message) + openModal(PromptNotice, errorNotice('Error deleting profile:', e)) } } @@ -138,7 +140,7 @@ saveCustomProfile(profile) refreshSettings() } catch (e) { - window.alert('Unable to import profile: \n' + e.message) + openModal(PromptNotice, errorNotice('Unable to import profile:', e)) } } } @@ -201,7 +203,7 @@ saveCustomProfile(chat.settings) refreshSettings() } catch (e) { - window.alert('Error saving profile: \n' + e.message) + openModal(PromptNotice, errorNotice('Error saving profile:', e)) } } diff --git a/src/lib/EditMessage.svelte b/src/lib/EditMessage.svelte index 7a9bd63..f3af648 100644 --- a/src/lib/EditMessage.svelte +++ b/src/lib/EditMessage.svelte @@ -7,7 +7,10 @@ import type { Message, Model, Chat } from './Types.svelte' import Fa from 'svelte-fa/src/fa.svelte' import { faTrash, faDiagramPredecessor, faDiagramNext, faCircleCheck, faPaperPlane, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons/index' - import { scrollIntoViewWithOffset } from './Util.svelte' + import { errorNotice, scrollIntoViewWithOffset } from './Util.svelte' + import { openModal } from 'svelte-modals' + import PromptConfirm from './PromptConfirm.svelte' + import PromptNotice from './PromptNotice.svelte' export let message:Message export let chatId:number @@ -115,24 +118,33 @@ waitingForDeleteConfirm = 0 if (message.summarized) { // is in a summary, so we're summarized - window.alert('Sorry, you can\'t delete a summarized message') + openModal(PromptNotice, errorNotice('Sorry, you can\'t delete a summarized message')) return } if (message.summary) { // We're linked to messages we're a summary of - if (window.confirm('Are you sure you want to delete this summary?\nYour session may be too long to submit again after you do.')) { - try { - deleteSummaryMessage(chatId, message.uuid) - } catch (e) { - window.alert('Unable to delete summary:\n' + e.message) - } + openModal(PromptConfirm, { + title: 'Delete Summary', + message: '

Are you sure you want to delete this summary?

Your session may be too long to submit again after you do.

', + asHtml: true, + class: 'is-warning', + confirmButtonClass: 'is-warning', + confirmButton: 'Delete Summary', + onConfirm: () => { + try { + deleteSummaryMessage(chatId, message.uuid) + } catch (e) { + openModal(PromptNotice, errorNotice('Unable to delete summary:', e)) + } + }, + onCancel: () => {} + }) + } else { + try { + deleteMessage(chatId, message.uuid) + } catch (e) { + openModal(PromptNotice, errorNotice('Unable to delete:', e)) } - return - } - try { - deleteMessage(chatId, message.uuid) - } catch (e) { - window.alert('Unable to delete:\n' + e.message) } } @@ -150,21 +162,21 @@ waitingForTruncateConfirm = 0 if (message.summarized) { // is in a summary, so we're summarized - window.alert('Sorry, you can\'t truncate a summarized message') + openModal(PromptNotice, errorNotice('Sorry, you can\'t truncate a summarized message')) return } try { truncateFromMessage(chatId, message.uuid) $submitExitingPromptsNow = true } catch (e) { - window.alert('Unable to delete:\n' + e.message) + openModal(PromptNotice, errorNotice('Unable to delete:', e)) } } const setSuppress = (value:boolean) => { if (message.summarized) { // is in a summary, so we're summarized - window.alert('Sorry, you can\'t suppress a summarized message') + openModal(PromptNotice, errorNotice('Sorry, you can\'t suppress a summarized message')) return } message.suppress = value diff --git a/src/lib/PromptNotice.svelte b/src/lib/PromptNotice.svelte new file mode 100644 index 0000000..5c1c65b --- /dev/null +++ b/src/lib/PromptNotice.svelte @@ -0,0 +1,50 @@ + + +{#if isOpen} +