Merge pull request #2955 from Yokayo/staging Add rename buttons for advanced formatting presets

bdaf7b9258cbb426abeb042549a4b0521c5f3395

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
5 files changed, +169 -58Ignore whitespace
public/index.html+6 -3
@@ -3178,9 +3178,10 @@
3178 </h4>3178 </h4>
3179 <div class="flex-container" title="Select your current Context Template" data-i18n="[title]Select your current Context Template">3179 <div class="flex-container" title="Select your current Context Template" data-i18n="[title]Select your current Context Template">
3180 <select id="context_presets" data-preset-manager-for="context" class="flex1 text_pole"></select>3180 <select id="context_presets" data-preset-manager-for="context" class="flex1 text_pole"></select>
3181 <div class="flex-container justifyCenter">3181 <div class="flex-container justifyCenter gap3px">
3182 <input type="file" hidden data-preset-manager-file="context" accept=".json, .settings">3182 <input type="file" hidden data-preset-manager-file="context" accept=".json, .settings">
3183 <i data-preset-manager-update="context" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i>3183 <i data-preset-manager-update="context" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i>
3184 <i data-preset-manager-rename="context" class="menu_button fa-pencil fa-solid" title="Rename current template" data-i18n="[title]Rename current template"></i>
3184 <i data-preset-manager-new="context" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i>3185 <i data-preset-manager-new="context" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i>
3185 <i data-preset-manager-import="context" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>3186 <i data-preset-manager-import="context" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>
3186 <i data-preset-manager-export="context" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>3187 <i data-preset-manager-export="context" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>
@@ -3289,9 +3290,10 @@
32893290
3290 <div class="flex-container" title="Select your current Instruct Template" data-i18n="[title]Select your current Instruct Template">3291 <div class="flex-container" title="Select your current Instruct Template" data-i18n="[title]Select your current Instruct Template">
3291 <select id="instruct_presets" data-preset-manager-for="instruct" class="flex1 text_pole"></select>3292 <select id="instruct_presets" data-preset-manager-for="instruct" class="flex1 text_pole"></select>
3292 <div class="flex-container margin0 justifyCenter">3293 <div class="flex-container margin0 justifyCenter gap3px">
3293 <input type="file" hidden data-preset-manager-file="instruct" accept=".json, .settings">3294 <input type="file" hidden data-preset-manager-file="instruct" accept=".json, .settings">
3294 <i data-preset-manager-update="instruct" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i>3295 <i data-preset-manager-update="instruct" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i>
3296 <i data-preset-manager-rename="instruct" class="menu_button fa-pencil fa-solid" title="Rename current template" data-i18n="[title]Rename current template"></i>
3295 <i data-preset-manager-new="instruct" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i>3297 <i data-preset-manager-new="instruct" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i>
3296 <i data-preset-manager-import="instruct" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>3298 <i data-preset-manager-import="instruct" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>
3297 <i data-preset-manager-export="instruct" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>3299 <i data-preset-manager-export="instruct" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>
@@ -3469,9 +3471,10 @@
34693471
3470 <div class="flex-container" title="Select your current System Prompt" data-i18n="[title]Select your current System Prompt">3472 <div class="flex-container" title="Select your current System Prompt" data-i18n="[title]Select your current System Prompt">
3471 <select id="sysprompt_select" data-preset-manager-for="sysprompt" class="flex1 text_pole"></select>3473 <select id="sysprompt_select" data-preset-manager-for="sysprompt" class="flex1 text_pole"></select>
3472 <div class="flex-container margin0 justifyCenter">3474 <div class="flex-container margin0 justifyCenter gap3px">
3473 <input type="file" hidden data-preset-manager-file="sysprompt" accept=".json, .settings">3475 <input type="file" hidden data-preset-manager-file="sysprompt" accept=".json, .settings">
3474 <i data-preset-manager-update="sysprompt" class="menu_button fa-solid fa-save" title="Update current prompt" data-i18n="[title]Update current prompt"></i>3476 <i data-preset-manager-update="sysprompt" class="menu_button fa-solid fa-save" title="Update current prompt" data-i18n="[title]Update current prompt"></i>
3477 <i data-preset-manager-rename="sysprompt" class="menu_button fa-pencil fa-solid" title="Rename current prompt" data-i18n="[title]Rename current prompt"></i>
3475 <i data-preset-manager-new="sysprompt" class="menu_button fa-solid fa-file-circle-plus" title="Save prompt as" data-i18n="[title]Save prompt as"></i>3478 <i data-preset-manager-new="sysprompt" class="menu_button fa-solid fa-file-circle-plus" title="Save prompt as" data-i18n="[title]Save prompt as"></i>
3476 <i data-preset-manager-import="sysprompt" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>3479 <i data-preset-manager-import="sysprompt" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i>
3477 <i data-preset-manager-export="sysprompt" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>3480 <i data-preset-manager-export="sysprompt" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i>
public/locales/ru-ru.json+71 -5
@@ -1720,7 +1720,7 @@
1720 "Proxy Preset": "Пресет для прокси",1720 "Proxy Preset": "Пресет для прокси",
1721 "Enter a name:": "Введите название:",1721 "Enter a name:": "Введите название:",
1722 "Are you sure you want to delete the selected profile?": "Вы точно хотите удалить выбранный профиль?",1722 "Are you sure you want to delete the selected profile?": "Вы точно хотите удалить выбранный профиль?",
1723 "instruct_enabled": "Включить Instruct-режим",1723 "instruct_enabled": "Вкл/выкл Instruct-режим",
1724 "Instruct Template": "Шаблон Instruct-режима",1724 "Instruct Template": "Шаблон Instruct-режима",
1725 "instruct_template_activation_regex_desc": "Автоматически активировать этот шаблон в момент подключения к API или выбора модели, если название модели соответствует этому рег. выражению.",1725 "instruct_template_activation_regex_desc": "Автоматически активировать этот шаблон в момент подключения к API или выбора модели, если название модели соответствует этому рег. выражению.",
1726 "instruct_bind_to_context": "При включении этой опции Шаблон контекста будет выбираться, исходя из выбранного в текущий момент Шаблона Instruct-режима, либо по вашему желанию.",1726 "instruct_bind_to_context": "При включении этой опции Шаблон контекста будет выбираться, исходя из выбранного в текущий момент Шаблона Instruct-режима, либо по вашему желанию.",
@@ -1730,11 +1730,11 @@
1730 "Export Advanced Formatting settings": "Экспорт настроек Расширенного форматирования",1730 "Export Advanced Formatting settings": "Экспорт настроек Расширенного форматирования",
1731 "Select your current System Prompt": "Выберите текущий системный промпт",1731 "Select your current System Prompt": "Выберите текущий системный промпт",
1732 "Prompt Content": "Текст промпта",1732 "Prompt Content": "Текст промпта",
1733 "Update current prompt": "Обновить текущий промпт",1733 "Update current prompt": "Сохранить промпт",
1734 "Save prompt as": "Сохранить как...",1734 "Save prompt as": "Сохранить как...",
1735 "Import template": "Импорт шаблона",1735 "Import template": "Импорт шаблона",
1736 "Export template": "Экспорт шаблона",1736 "Export template": "Экспорт шаблона",
1737 "Restore current prompt": "Восстановить текущий промпт",1737 "Restore current prompt": "Восстановить промпт",
1738 "comma delimited,no spaces between": "через запятую,без пробелов в промежутках",1738 "comma delimited,no spaces between": "через запятую,без пробелов в промежутках",
1739 "User Message Sequences": "Строки для сообщений пользователя",1739 "User Message Sequences": "Строки для сообщений пользователя",
1740 "Assistant Message Sequences": "Строки для сообщений ассистента",1740 "Assistant Message Sequences": "Строки для сообщений ассистента",
@@ -1757,7 +1757,7 @@
1757 "Preset was not deleted from server": "Пресет не удалён с сервера",1757 "Preset was not deleted from server": "Пресет не удалён с сервера",
1758 "Preset deleted": "Пресет удалён",1758 "Preset deleted": "Пресет удалён",
1759 "Delete the preset?": "Удалить пресет?",1759 "Delete the preset?": "Удалить пресет?",
1760 "Preset updated": "Пресет обновлён",1760 "Preset updated": "Пресет сохранён",
1761 "Entered reverse proxy address is not a valid URL": "Введённый адрес прокси невалиден",1761 "Entered reverse proxy address is not a valid URL": "Введённый адрес прокси невалиден",
1762 "An error occurred while counting tokens: Token budget exceeded.": "Ошибка при подсчёте токенов: Превышен бюджет токенов",1762 "An error occurred while counting tokens: Token budget exceeded.": "Ошибка при подсчёте токенов: Превышен бюджет токенов",
1763 "An error occurred while counting tokens: Invalid character name": "Ошибка при подсчёте токенов: Невалидное имя персонажа",1763 "An error occurred while counting tokens: Invalid character name": "Ошибка при подсчёте токенов: Невалидное имя персонажа",
@@ -1893,5 +1893,71 @@
1893 "Base": "Основание",1893 "Base": "Основание",
1894 "DRY_Base_desc": "Определяет, насколько быстро возрастает штраф с увеличением длины строки.",1894 "DRY_Base_desc": "Определяет, насколько быстро возрастает штраф с увеличением длины строки.",
1895 "Allowed Length": "Допустимая длина",1895 "Allowed Length": "Допустимая длина",
1896 "DRY_Allowed_Length_desc": "Длина повторяющейся строки, при превышении которой DRY начинает налагать штраф."1896 "DRY_Allowed_Length_desc": "Длина повторяющейся строки, при превышении которой DRY начинает налагать штраф.",
1897 "Invalid data provided for master import": "Глоб. импорт не может быть выполнен по причине невалидности данных",
1898 "Importing instruct template...": "Импортируем...",
1899 "Instruct template detected": "Обнаружен шаблон Instruct-режима",
1900 "Importing as context template...": "Импортируем...",
1901 "Context template detected": "Обнаружен шаблон контекста",
1902 "Importing as system prompt...": "Импортируем...",
1903 "System prompt detected": "Обнаружен системный промпт",
1904 "Importing as settings preset...": "Импортируем...",
1905 "Text Completion settings detected": "Обнаружены настройки Text Completion",
1906 "No valid sections found in imported data": "Не найдено ни одной валидной секции данных",
1907 "No sections selected for import": "Не выбрано ни одной секции для импорта",
1908 "Import": "Импортировать",
1909 "Imported ${0} settings: ${1}": "Импортировано ${0} настроек: ${1}",
1910 "Export": "Экспортировать",
1911 "No sections selected for export": "Не выбрано ни одной секции для экспорта",
1912 "Cannot update GUI preset": "Пресет для GUI обновить невозможно",
1913 "Template updated": "Шаблон сохранён",
1914 "Hint: Use a character/group name to bind preset to a specific chat.": "Совет: введите имя персонажа/группы, чтобы привязать пресет к определённому чату.",
1915 "Preset name:": "Название пресета:",
1916 "Template name:": "Название шаблона:",
1917 "Preset saved": "Пресет сохранён",
1918 "Template saved": "Шаблон сохранён",
1919 "Preset could not be saved": "Не удалось сохранить пресет",
1920 "Preset could not be renamed": "Не удалось обновить пресет",
1921 "Preset renamed": "Пресет переименован",
1922 "Template renamed": "Шаблон переименован",
1923 "Cannot delete GUI preset": "Пресет для GUI удалить невозможно",
1924 "Failed to restore default preset": "Не удалось восстановить пресет по умолчанию",
1925 "Failed to restore default template": "Не удалось восстановить шаблон по умолчанию",
1926 "Rename preset": "Переименовать пресет",
1927 "Rename template": "Переименовать шаблон",
1928 "Enter a new name:": "Введите новое название:",
1929 "Preset imported": "Пресет импортирован",
1930 "Template imported": "Шаблон импортирован",
1931 "Delete this preset?": "Удалить этот пресет?",
1932 "Delete this template?": "Удалить этот шаблон?",
1933 "This action is irreversible and your current settings will be overwritten.": "Отменить это действие невозможно. Ваши текущие настройки будут перезаписаны.",
1934 "Preset deleted": "Пресет удалён",
1935 "Template deleted": "Шаблон удалён",
1936 "Template was not deleted from server": "Шаблон не удалён с сервера",
1937 "Cannot restore GUI preset": "Пресет для Gui восстановить нельзя",
1938 "Default preset cannot be restored": "Невозможно восстановить пресет по умолчанию",
1939 "Default template cannot be restored": "Невозможно восстановить шаблон по умолчанию",
1940 "Resetting a <b>default preset</b> will restore the default settings": "Сброс <b>стандартного пресета</b> восстановит настройки по умолчанию.",
1941 "Resetting a <b>default template</b> will restore the default settings.": "Сброс <b>стандартного шаблона</b> восстановит настройки по умолчанию.",
1942 "Are you sure?": "Вы уверены?",
1943 "Default preset restored": "Стандартный пресет восстановлен",
1944 "Default template restored": "Стандартный шаблон восстановлен",
1945 "Resetting a <b>custom preset</b> will restore to the last saved state.": "Сброс <b>пользовательского пресета</b> откатит его к последнему сохранённому состоянию.",
1946 "Resetting a <b>custom template</b> will restore to the last saved state.": "Сброс <b>пользовательского шаблона</b> откатит его к последнему сохранённому состоянию.",
1947 "Preset restored": "Пресет восстановлен",
1948 "Template restored": "Шаблон восстановлен",
1949 "Update current template": "Сохранить шаблон",
1950 "Rename current template": "Переименовать шаблон",
1951 "Save template as": "Сохранить как...",
1952 "Restore current template": "Восстановить шаблон",
1953 "Delete the template": "Удалить шаблон",
1954 "Rename current prompt": "Переименовать промпт",
1955 "Select your current Context Template": "Выберите активный шаблон контекста",
1956 "Select your current Instruct Template": "Выберите активный шаблон Instruct-режима",
1957 "and connect to an": "и подключитесь к",
1958 "You can add more": "Можете добавить больше",
1959 "from other websites": "с других сайтов.",
1960 "Go to the": "Загляните в",
1961 "to install additional features.": ", чтобы установить разные дополнительные ресурсы.",
1962 "or_welcome": "; также доступен"
1897}1963}
public/script.js+1 -1
@@ -6755,7 +6755,7 @@ export async function saveSettings(type) {
6755 eventSource.emit(event_types.SETTINGS_UPDATED);6755 eventSource.emit(event_types.SETTINGS_UPDATED);
6756 },6756 },
6757 error: function (jqXHR, exception) {6757 error: function (jqXHR, exception) {
6758 toastr.error(t`Check the server connection and reload the page to prevent data loss.t`, t`Settings could not be saved`);6758 toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Settings could not be saved`);
6759 console.log(exception);6759 console.log(exception);
6760 console.log(jqXHR);6760 console.log(jqXHR);
6761 },6761 },
public/scripts/preset-manager.js+87 -45
@@ -34,6 +34,7 @@ import {
34 textgenerationwebui_settings as textgen_settings,34 textgenerationwebui_settings as textgen_settings,
35} from './textgen-settings.js';35} from './textgen-settings.js';
36import { download, parseJsonFile, waitUntilCondition } from './utils.js';36import { download, parseJsonFile, waitUntilCondition } from './utils.js';
37import { t } from './i18n.js';
3738
38const presetManagers = {};39const presetManagers = {};
3940
@@ -194,32 +195,32 @@ class PresetManager {
194 */195 */
195 static async performMasterImport(data, fileName) {196 static async performMasterImport(data, fileName) {
196 if (!data || typeof data !== 'object') {197 if (!data || typeof data !== 'object') {
197 toastr.error('Invalid data provided for master import');198 toastr.error(t`Invalid data provided for master import`);
198 return;199 return;
199 }200 }
200201
201 // Check for legacy file imports202 // Check for legacy file imports
202 // 1. Instruct Template203 // 1. Instruct Template
203 if (this.isPossiblyInstructData(data)) {204 if (this.isPossiblyInstructData(data)) {
204 toastr.info('Importing instruct template...', 'Instruct template detected');205 toastr.info(t`Importing instruct template...`, t`Instruct template detected`);
205 return await getPresetManager('instruct').savePreset(data.name, data);206 return await getPresetManager('instruct').savePreset(data.name, data);
206 }207 }
207208
208 // 2. Context Template209 // 2. Context Template
209 if (this.isPossiblyContextData(data)) {210 if (this.isPossiblyContextData(data)) {
210 toastr.info('Importing as context template...', 'Context template detected');211 toastr.info(t`Importing as context template...`, t`Context template detected`);
211 return await getPresetManager('context').savePreset(data.name, data);212 return await getPresetManager('context').savePreset(data.name, data);
212 }213 }
213214
214 // 3. System Prompt215 // 3. System Prompt
215 if (this.isPossiblySystemPromptData(data)) {216 if (this.isPossiblySystemPromptData(data)) {
216 toastr.info('Importing as system prompt...', 'System prompt detected');217 toastr.info(t`Importing as system prompt...`, t`System prompt detected`);
217 return await getPresetManager('sysprompt').savePreset(data.name, data);218 return await getPresetManager('sysprompt').savePreset(data.name, data);
218 }219 }
219220
220 // 4. Text Completion settings221 // 4. Text Completion settings
221 if (this.isPossiblyTextCompletionData(data)) {222 if (this.isPossiblyTextCompletionData(data)) {
222 toastr.info('Importing as settings preset...', 'Text Completion settings detected');223 toastr.info(t`Importing as settings preset...`, t`Text Completion settings detected`);
223 return await getPresetManager('textgenerationwebui').savePreset(fileName, data);224 return await getPresetManager('textgenerationwebui').savePreset(fileName, data);
224 }225 }
225226
@@ -231,7 +232,7 @@ class PresetManager {
231 }232 }
232233
233 if (validSections.length === 0) {234 if (validSections.length === 0) {
234 toastr.error('No valid sections found in imported data');235 toastr.error(t`No valid sections found in imported data`);
235 return;236 return;
236 }237 }
237238
@@ -242,8 +243,8 @@ class PresetManager {
242243
243 const html = $(await renderTemplateAsync('masterImport', { sections: sectionNames }));244 const html = $(await renderTemplateAsync('masterImport', { sections: sectionNames }));
244 const popup = new Popup(html, POPUP_TYPE.CONFIRM, '', {245 const popup = new Popup(html, POPUP_TYPE.CONFIRM, '', {
245 okButton: 'Import',246 okButton: t`Import`,
246 cancelButton: 'Cancel',247 cancelButton: t`Cancel`,
247 });248 });
248249
249 const result = await popup.show();250 const result = await popup.show();
@@ -257,7 +258,7 @@ class PresetManager {
257 const confirmedSections = html.find('input:checked').map((_, el) => el instanceof HTMLInputElement && el.value).get();258 const confirmedSections = html.find('input:checked').map((_, el) => el instanceof HTMLInputElement && el.value).get();
258259
259 if (confirmedSections.length === 0) {260 if (confirmedSections.length === 0) {
260 toastr.info('No sections selected for import');261 toastr.info(t`No sections selected for import`);
261 return;262 return;
262 }263 }
263264
@@ -270,7 +271,7 @@ class PresetManager {
270 }271 }
271 }272 }
272273
273 toastr.success(`Imported ${importedSections.length} settings: ${importedSections.join(', ')}`);274 toastr.success(t`Imported ${importedSections.length} settings: ${importedSections.join(', ')}`);
274 }275 }
275276
276 /**277 /**
@@ -285,8 +286,8 @@ class PresetManager {
285 const html = $(await renderTemplateAsync('masterExport', { sections: sectionNames }));286 const html = $(await renderTemplateAsync('masterExport', { sections: sectionNames }));
286287
287 const popup = new Popup(html, POPUP_TYPE.CONFIRM, '', {288 const popup = new Popup(html, POPUP_TYPE.CONFIRM, '', {
288 okButton: 'Export',289 okButton: t`Export`,
289 cancelButton: 'Cancel',290 cancelButton: t`Cancel`,
290 });291 });
291292
292 const result = await popup.show();293 const result = await popup.show();
@@ -300,7 +301,7 @@ class PresetManager {
300 const data = {};301 const data = {};
301302
302 if (confirmedSections.length === 0) {303 if (confirmedSections.length === 0) {
303 toastr.info('No sections selected for export');304 toastr.info(t`No sections selected for export`);
304 return;305 return;
305 }306 }
306307
@@ -328,7 +329,7 @@ class PresetManager {
328 * @returns {any} Preset value329 * @returns {any} Preset value
329 */330 */
330 findPreset(name) {331 findPreset(name) {
331 return $(this.select).find('option').filter(function() {332 return $(this.select).find('option').filter(function () {
332 return $(this).text() === name;333 return $(this).text() === name;
333 }).val();334 }).val();
334 }335 }
@@ -354,7 +355,7 @@ class PresetManager {
354 * @param {string} value Preset option value355 * @param {string} value Preset option value
355 */356 */
356 selectPreset(value) {357 selectPreset(value) {
357 const option = $(this.select).filter(function() {358 const option = $(this.select).filter(function () {
358 return $(this).val() === value;359 return $(this).val() === value;
359 });360 });
360 option.prop('selected', true);361 option.prop('selected', true);
@@ -366,21 +367,21 @@ class PresetManager {
366 console.log(selected);367 console.log(selected);
367368
368 if (selected.val() == 'gui') {369 if (selected.val() == 'gui') {
369 toastr.info('Cannot update GUI preset');370 toastr.info(t`Cannot update GUI preset`);
370 return;371 return;
371 }372 }
372373
373 const name = selected.text();374 const name = selected.text();
374 await this.savePreset(name);375 await this.savePreset(name);
375376
376 const successToast = !this.isAdvancedFormatting() ? 'Preset updated' : 'Template updated';377 const successToast = !this.isAdvancedFormatting() ? t`Preset updated` : t`Template updated`;
377 toastr.success(successToast);378 toastr.success(successToast);
378 }379 }
379380
380 async savePresetAs() {381 async savePresetAs() {
381 const inputValue = this.getSelectedPresetName();382 const inputValue = this.getSelectedPresetName();
382 const popupText = !this.isAdvancedFormatting() ? '<h4>Hint: Use a character/group name to bind preset to a specific chat.</h4>' : '';383 const popupText = !this.isAdvancedFormatting() ? '<h4>' + t`Hint: Use a character/group name to bind preset to a specific chat.` + '</h4>' : '';
383 const headerText = !this.isAdvancedFormatting() ? 'Preset name:' : 'Template name:';384 const headerText = !this.isAdvancedFormatting() ? t`Preset name:` : t`Template name:`;
384 const name = await Popup.show.input(headerText, popupText, inputValue);385 const name = await Popup.show.input(headerText, popupText, inputValue);
385 if (!name) {386 if (!name) {
386 console.log('Preset name not provided');387 console.log('Preset name not provided');
@@ -389,7 +390,7 @@ class PresetManager {
389390
390 await this.savePreset(name);391 await this.savePreset(name);
391392
392 const successToast = !this.isAdvancedFormatting() ? 'Preset saved' : 'Template saved';393 const successToast = !this.isAdvancedFormatting() ? t`Preset saved` : t`Template saved`;
393 toastr.success(successToast);394 toastr.success(successToast);
394 }395 }
395396
@@ -411,7 +412,7 @@ class PresetManager {
411 });412 });
412413
413 if (!response.ok) {414 if (!response.ok) {
414 toastr.error('Check the server connection and reload the page to prevent data loss.', 'Preset could not be saved');415 toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Preset could not be saved`);
415 console.error('Preset could not be saved', response);416 console.error('Preset could not be saved', response);
416 throw new Error('Preset could not be saved');417 throw new Error('Preset could not be saved');
417 }418 }
@@ -422,6 +423,19 @@ class PresetManager {
422 this.updateList(name, preset);423 this.updateList(name, preset);
423 }424 }
424425
426 async renamePreset(newName) {
427 const oldName = this.getSelectedPresetName();
428 try {
429 await this.savePreset(newName);
430 await this.deletePreset(oldName);
431 } catch (error) {
432 toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Preset could not be renamed`);
433 console.error('Preset could not be renamed', error);
434 throw new Error('Preset could not be renamed');
435 }
436
437 }
438
425 getPresetList() {439 getPresetList() {
426 let presets = [];440 let presets = [];
427 let preset_names = {};441 let preset_names = {};
@@ -585,13 +599,14 @@ class PresetManager {
585 return settings;599 return settings;
586 }600 }
587601
588 async deleteCurrentPreset() {602 // pass no arguments to delete current preset
603 async deletePreset(name) {
589 const { preset_names, presets } = this.getPresetList();604 const { preset_names, presets } = this.getPresetList();
590 const value = this.getSelectedPreset();605 const value = name ? (this.isKeyedApi() ? this.findPreset(name) : name) : this.getSelectedPreset();
591 const nameToDelete = this.getSelectedPresetName();606 const nameToDelete = name || this.getSelectedPresetName();
592607
593 if (value == 'gui') {608 if (value == 'gui') {
594 toastr.info('Cannot delete GUI preset');609 toastr.info(t`Cannot delete GUI preset`);
595 return;610 return;
596 }611 }
597612
@@ -605,7 +620,10 @@ class PresetManager {
605 delete preset_names[nameToDelete];620 delete preset_names[nameToDelete];
606 }621 }
607622
608 if (Object.keys(preset_names).length) {623 // switch in UI only when deleting currently selected preset
624 const switchPresets = !name || this.getSelectedPresetName() == name;
625
626 if (Object.keys(preset_names).length && switchPresets) {
609 const nextPresetName = Object.keys(preset_names)[0];627 const nextPresetName = Object.keys(preset_names)[0];
610 const newValue = preset_names[nextPresetName];628 const newValue = preset_names[nextPresetName];
611 $(this.select).find(`option[value="${newValue}"]`).attr('selected', 'true');629 $(this.select).find(`option[value="${newValue}"]`).attr('selected', 'true');
@@ -629,7 +647,7 @@ class PresetManager {
629 });647 });
630648
631 if (!response.ok) {649 if (!response.ok) {
632 const errorToast = !this.isAdvancedFormatting() ? 'Failed to restore default preset' : 'Failed to restore default template';650 const errorToast = !this.isAdvancedFormatting() ? t`Failed to restore default preset` : t`Failed to restore default template`;
633 toastr.error(errorToast);651 toastr.error(errorToast);
634 return;652 return;
635 }653 }
@@ -721,7 +739,8 @@ async function waitForConnection() {
721export async function initPresetManager() {739export async function initPresetManager() {
722 eventSource.on(event_types.CHAT_CHANGED, autoSelectPreset);740 eventSource.on(event_types.CHAT_CHANGED, autoSelectPreset);
723 registerPresetManagers();741 registerPresetManagers();
724 SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'preset',742 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
743 name: 'preset',
725 callback: presetCommandCallback,744 callback: presetCommandCallback,
726 returns: 'current preset',745 returns: 'current preset',
727 unnamedArgumentList: [746 unnamedArgumentList: [
@@ -774,6 +793,29 @@ export async function initPresetManager() {
774 await presetManager.savePresetAs();793 await presetManager.savePresetAs();
775 });794 });
776795
796 $(document).on('click', '[data-preset-manager-rename]', async function () {
797 const apiId = $(this).data('preset-manager-rename');
798 const presetManager = getPresetManager(apiId);
799
800 if (!presetManager) {
801 console.warn(`Preset Manager not found for API: ${apiId}`);
802 return;
803 }
804
805 const popupHeader = !presetManager.isAdvancedFormatting() ? t`Rename preset` : t`Rename template`;
806 const oldName = presetManager.getSelectedPresetName();
807 const newName = await Popup.show.input(popupHeader, t`Enter a new name:`, oldName);
808 if (!newName || oldName === newName) {
809 console.debug(!presetManager.isAdvancedFormatting() ? 'Preset rename cancelled' : 'Template rename cancelled');
810 return;
811 }
812
813 await presetManager.renamePreset(newName);
814
815 const successToast = !presetManager.isAdvancedFormatting() ? t`Preset renamed` : t`Template renamed`;
816 toastr.success(successToast);
817 });
818
777 $(document).on('click', '[data-preset-manager-export]', async function () {819 $(document).on('click', '[data-preset-manager-export]', async function () {
778 const apiId = $(this).data('preset-manager-export');820 const apiId = $(this).data('preset-manager-export');
779 const presetManager = getPresetManager(apiId);821 const presetManager = getPresetManager(apiId);
@@ -816,7 +858,7 @@ export async function initPresetManager() {
816 data['name'] = name;858 data['name'] = name;
817859
818 await presetManager.savePreset(name, data);860 await presetManager.savePreset(name, data);
819 const successToast = !presetManager.isAdvancedFormatting() ? 'Preset imported' : 'Template imported';861 const successToast = !presetManager.isAdvancedFormatting() ? t`Preset imported` : t`Template imported`;
820 toastr.success(successToast);862 toastr.success(successToast);
821 e.target.value = null;863 e.target.value = null;
822 });864 });
@@ -830,19 +872,19 @@ export async function initPresetManager() {
830 return;872 return;
831 }873 }
832874
833 const headerText = !presetManager.isAdvancedFormatting() ? 'Delete this preset?' : 'Delete this template?';875 const headerText = !presetManager.isAdvancedFormatting() ? t`Delete this preset?` : t`Delete this template?`;
834 const confirm = await Popup.show.confirm(headerText, 'This action is irreversible and your current settings will be overwritten.');876 const confirm = await Popup.show.confirm(headerText, t`This action is irreversible and your current settings will be overwritten.`);
835 if (!confirm) {877 if (!confirm) {
836 return;878 return;
837 }879 }
838880
839 const result = await presetManager.deleteCurrentPreset();881 const result = await presetManager.deletePreset();
840882
841 if (result) {883 if (result) {
842 const successToast = !presetManager.isAdvancedFormatting() ? 'Preset deleted' : 'Template deleted';884 const successToast = !presetManager.isAdvancedFormatting() ? t`Preset deleted` : t`Template deleted`;
843 toastr.success(successToast);885 toastr.success(successToast);
844 } else {886 } else {
845 const warningToast = !presetManager.isAdvancedFormatting() ? 'Preset was not deleted from server' : 'Template was not deleted from server';887 const warningToast = !presetManager.isAdvancedFormatting() ? t`Preset was not deleted from server` : t`Template was not deleted from server`;
846 toastr.warning(warningToast);888 toastr.warning(warningToast);
847 }889 }
848890
@@ -862,7 +904,7 @@ export async function initPresetManager() {
862 const data = await presetManager.getDefaultPreset(name);904 const data = await presetManager.getDefaultPreset(name);
863905
864 if (name == 'gui') {906 if (name == 'gui') {
865 toastr.info('Cannot restore GUI preset');907 toastr.info(t`Cannot restore GUI preset`);
866 return;908 return;
867 }909 }
868910
@@ -872,37 +914,37 @@ export async function initPresetManager() {
872914
873 if (data.isDefault) {915 if (data.isDefault) {
874 if (Object.keys(data.preset).length === 0) {916 if (Object.keys(data.preset).length === 0) {
875 const errorToast = !presetManager.isAdvancedFormatting() ? 'Default preset cannot be restored' : 'Default template cannot be restored';917 const errorToast = !presetManager.isAdvancedFormatting() ? t`Default preset cannot be restored` : t`Default template cannot be restored`;
876 toastr.error(errorToast);918 toastr.error(errorToast);
877 return;919 return;
878 }920 }
879921
880 const confirmText = !presetManager.isAdvancedFormatting()922 const confirmText = !presetManager.isAdvancedFormatting()
881 ? 'Resetting a <b>default preset</b> will restore the default settings.'923 ? t`Resetting a <b>default preset</b> will restore the default settings.`
882 : 'Resetting a <b>default template</b> will restore the default settings.';924 : t`Resetting a <b>default template</b> will restore the default settings.`;
883 const confirm = await Popup.show.confirm('Are you sure?', confirmText);925 const confirm = await Popup.show.confirm(t`Are you sure?`, confirmText);
884 if (!confirm) {926 if (!confirm) {
885 return;927 return;
886 }928 }
887929
888 await presetManager.deleteCurrentPreset();930 await presetManager.deletePreset();
889 await presetManager.savePreset(name, data.preset);931 await presetManager.savePreset(name, data.preset);
890 const option = presetManager.findPreset(name);932 const option = presetManager.findPreset(name);
891 presetManager.selectPreset(option);933 presetManager.selectPreset(option);
892 const successToast = !presetManager.isAdvancedFormatting() ? 'Default preset restored' : 'Default template restored';934 const successToast = !presetManager.isAdvancedFormatting() ? t`Default preset restored` : t`Default template restored`;
893 toastr.success(successToast);935 toastr.success(successToast);
894 } else {936 } else {
895 const confirmText = !presetManager.isAdvancedFormatting()937 const confirmText = !presetManager.isAdvancedFormatting()
896 ? 'Resetting a <b>custom preset</b> will restore to the last saved state.'938 ? t`Resetting a <b>custom preset</b> will restore to the last saved state.`
897 : 'Resetting a <b>custom template</b> will restore to the last saved state.';939 : t`Resetting a <b>custom template</b> will restore to the last saved state.`;
898 const confirm = await Popup.show.confirm('Are you sure?', confirmText);940 const confirm = await Popup.show.confirm(t`Are you sure?`, confirmText);
899 if (!confirm) {941 if (!confirm) {
900 return;942 return;
901 }943 }
902944
903 const option = presetManager.findPreset(name);945 const option = presetManager.findPreset(name);
904 presetManager.selectPreset(option);946 presetManager.selectPreset(option);
905 const successToast = !presetManager.isAdvancedFormatting() ? 'Preset restored' : 'Template restored';947 const successToast = !presetManager.isAdvancedFormatting() ? t`Preset restored` : t`Template restored`;
906 toastr.success(successToast);948 toastr.success(successToast);
907 }949 }
908 });950 });
public/scripts/templates/welcome.html+4 -4
@@ -10,7 +10,7 @@
10 <span data-i18n="Click _space">Click </span>10 <span data-i18n="Click _space">Click </span>
11 <button class="menu_button menu_button_icon drawer-opener inline-flex" data-target="sys-settings-button">11 <button class="menu_button menu_button_icon drawer-opener inline-flex" data-target="sys-settings-button">
12 <i class="fa-solid fa-plug"></i>12 <i class="fa-solid fa-plug"></i>
13 <span data-i18n="[title]API Connections">API Connections</span>13 <span data-i18n="API Connections">API Connections</span>
14 </button>14 </button>
15 <span data-i18n="and connect to an">and connect to an</span>15 <span data-i18n="and connect to an">and connect to an</span>
16 <a href="https://docs.sillytavern.app/usage/api-connections/" target="_blank">16 <a href="https://docs.sillytavern.app/usage/api-connections/" target="_blank">
@@ -21,7 +21,7 @@
21 <span data-i18n="Click _space">Click </span>21 <span data-i18n="Click _space">Click </span>
22 <button class="menu_button menu_button_icon drawer-opener inline-flex" data-target="rightNavHolder">22 <button class="menu_button menu_button_icon drawer-opener inline-flex" data-target="rightNavHolder">
23 <i class="fa-solid fa-address-card"></i>23 <i class="fa-solid fa-address-card"></i>
24 <span data-i18n="[title]Character Management">Character Management</span>24 <span data-i18n="Character Management">Character Management</span>
25 </button>25 </button>
26 <span data-i18n="and pick a character."> and pick a character.</span>26 <span data-i18n="and pick a character."> and pick a character.</span>
27 </li>27 </li>
@@ -33,7 +33,7 @@
33 <i class="fa-solid fa-image-portrait"></i>33 <i class="fa-solid fa-image-portrait"></i>
34 <span data-i18n="Sample characters">Sample characters</span>34 <span data-i18n="Sample characters">Sample characters</span>
35 </button>35 </button>
36 <span data-i18n="or">or</span>36 <span data-i18n="or_welcome">or</span>
37 <button class="external_import_button menu_button menu_button_icon inline-flex">37 <button class="external_import_button menu_button menu_button_icon inline-flex">
38 <i class="fa-solid fa-cloud-arrow-down"></i>38 <i class="fa-solid fa-cloud-arrow-down"></i>
39 <span data-i18n="Import Characters">Import characters</span>39 <span data-i18n="Import Characters">Import characters</span>
@@ -48,7 +48,7 @@
4848
49 <button class="menu_button menu_button_icon drawer-opener inline-flex" data-target="extensions-settings-button">49 <button class="menu_button menu_button_icon drawer-opener inline-flex" data-target="extensions-settings-button">
50 <i class="fa-solid fa-cubes"></i>50 <i class="fa-solid fa-cubes"></i>
51 <span data-i18n="[title]Extensions">Extensions</span>51 <span data-i18n="Extensions">Extensions</span>
52 </button>52 </button>
5353
54 <span data-i18n="to install additional features.">to install additional features.</span>54 <span data-i18n="to install additional features.">to install additional features.</span>