Remove all connections button for the popups
| @@ -236,6 +236,7 @@ import { | |||
| 236 | updatePersonaConnectionsAvatarList, | 236 | updatePersonaConnectionsAvatarList, |
| 237 | getConnectedPersonas, | 237 | getConnectedPersonas, |
| 238 | askForPersonaSelection, | 238 | askForPersonaSelection, |
| 239 | getCurrentConnectionObj, | ||
| 239 | } from './scripts/personas.js'; | 240 | } from './scripts/personas.js'; |
| 240 | import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js'; | 241 | import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js'; |
| 241 | import { hideLoader, showLoader } from './scripts/loader.js'; | 242 | import { hideLoader, showLoader } from './scripts/loader.js'; |
| @@ -9995,6 +9996,7 @@ jQuery(async function () { | |||
| 9995 | const selectedPersona = await askForPersonaSelection(t`Persona Connections`, message, connections, { | 9996 | const selectedPersona = await askForPersonaSelection(t`Persona Connections`, message, connections, { |
| 9996 | okButton: t`Ok`, | 9997 | okButton: t`Ok`, |
| 9997 | highlightPersonas: true, | 9998 | highlightPersonas: true, |
| 9999 | targetedChar: getCurrentConnectionObj(), | ||
| 9998 | shiftClickHandler: (element, ev) => { | 10000 | shiftClickHandler: (element, ev) => { |
| 9999 | 10001 | ||
| 10000 | const personaId = $(element).attr('data-pid'); | 10002 | const personaId = $(element).attr('data-pid'); |
| @@ -561,9 +561,10 @@ export function updatePersonaConnectionsAvatarList() { | |||
| 561 | * @param {string} [options.okButton='None'] - The label for the OK button | 561 | * @param {string} [options.okButton='None'] - The label for the OK button |
| 562 | * @param {(element: HTMLElement, ev: MouseEvent) => any} [options.shiftClickHandler] - A function to handle shift-click | 562 | * @param {(element: HTMLElement, ev: MouseEvent) => any} [options.shiftClickHandler] - A function to handle shift-click |
| 563 | * @param {boolean|string[]} [options.highlightPersonas=false] - Whether to highlight personas - either by providing a list of persona keys, or true to highlight all present in current chat | 563 | * @param {boolean|string[]} [options.highlightPersonas=false] - Whether to highlight personas - either by providing a list of persona keys, or true to highlight all present in current chat |
| 564 | * @param {PersonaConnection} [options.targetedChar] - The targeted character or gorup for this persona selection | ||
| 564 | * @returns {Promise<string?>} - A promise that resolves to the selected persona id or null if no selection was made | 565 | * @returns {Promise<string?>} - A promise that resolves to the selected persona id or null if no selection was made |
| 565 | */ | 566 | */ |
| 566 | export async function askForPersonaSelection(title, text, personas, { okButton = 'None', shiftClickHandler = undefined, highlightPersonas = false } = {}) { | 567 | export async function askForPersonaSelection(title, text, personas, { okButton = 'None', shiftClickHandler = undefined, highlightPersonas = false, targetedChar = undefined } = {}) { |
| 567 | const content = document.createElement('div'); | 568 | const content = document.createElement('div'); |
| 568 | const titleElement = document.createElement('h3'); | 569 | const titleElement = document.createElement('h3'); |
| 569 | titleElement.textContent = title; | 570 | titleElement.textContent = title; |
| @@ -581,7 +582,7 @@ export async function askForPersonaSelection(title, text, personas, { okButton = | |||
| 581 | if (personas.length > 0) | 582 | if (personas.length > 0) |
| 582 | buildPersonaAvatarList(personaListBlock, personas, { interactable: true }); | 583 | buildPersonaAvatarList(personaListBlock, personas, { interactable: true }); |
| 583 | else | 584 | else |
| 584 | personaListBlock.textContent = '[No personas]'; | 585 | personaListBlock.textContent = t`[Currently no personas connected]`; |
| 585 | 586 | ||
| 586 | const personasToHighlight = highlightPersonas instanceof Array ? highlightPersonas : (highlightPersonas ? getPersonasOfCurrentChat() : []); | 587 | const personasToHighlight = highlightPersonas instanceof Array ? highlightPersonas : (highlightPersonas ? getPersonasOfCurrentChat() : []); |
| 587 | 588 | ||
| @@ -605,7 +606,35 @@ export async function askForPersonaSelection(title, text, personas, { okButton = | |||
| 605 | } | 606 | } |
| 606 | }); | 607 | }); |
| 607 | 608 | ||
| 608 | const popup = new Popup(content, POPUP_TYPE.TEXT, '', { okButton: okButton }); | 609 | /** @type {import('./popup.js').CustomPopupButton[]} */ |
| 610 | const customButtons = []; | ||
| 611 | if (targetedChar) { | ||
| 612 | customButtons.push({ | ||
| 613 | text: t`Remove All Connections`, | ||
| 614 | result: 2, | ||
| 615 | action: () => { | ||
| 616 | for (const [personaId, description] of Object.entries(power_user.persona_descriptions)) { | ||
| 617 | /** @type {PersonaConnection[]} */ | ||
| 618 | const connections = description.connections; | ||
| 619 | if (connections) { | ||
| 620 | power_user.persona_descriptions[personaId].connections = connections.filter(c => { | ||
| 621 | if (targetedChar.type == c.type && targetedChar.id == c.id) return false; | ||
| 622 | return true; | ||
| 623 | }); | ||
| 624 | } | ||
| 625 | } | ||
| 626 | |||
| 627 | saveSettingsDebounced(); | ||
| 628 | updatePersonaConnectionsAvatarList(); | ||
| 629 | if (power_user.persona_show_notifications) { | ||
| 630 | const name = targetedChar.type == 'character' ? characters[targetedChar.id]?.name : groups[targetedChar.id]?.name; | ||
| 631 | toastr.info(t`All connections to ${name} have been removed.`, t`Personas unlocked`); | ||
| 632 | } | ||
| 633 | }, | ||
| 634 | }); | ||
| 635 | } | ||
| 636 | |||
| 637 | const popup = new Popup(content, POPUP_TYPE.TEXT, '', { okButton: okButton, customButtons: customButtons }); | ||
| 609 | const result = await popup.show(); | 638 | const result = await popup.show(); |
| 610 | return Number(result) > 100 ? personas[Number(result) - 100] : null; | 639 | return Number(result) > 100 ? personas[Number(result) - 100] : null; |
| 611 | } | 640 | } |
| @@ -903,8 +932,7 @@ async function lockPersona(type = 'chat') { | |||
| 903 | break; | 932 | break; |
| 904 | } | 933 | } |
| 905 | case 'character': { | 934 | case 'character': { |
| 906 | const newConnection = menu_type === 'character_edit' ? { type: 'character', id: characters[this_chid]?.avatar } : | 935 | const newConnection = getCurrentConnectionObj(); |
| 907 | menu_type === 'group_edit' ? { type: 'group', id: selected_group } : null; | ||
| 908 | /** @type {PersonaConnection[]} */ | 936 | /** @type {PersonaConnection[]} */ |
| 909 | const connections = power_user.persona_descriptions[user_avatar].connections?.filter(c => !isPersonaConnectionLocked(c)) ?? []; | 937 | const connections = power_user.persona_descriptions[user_avatar].connections?.filter(c => !isPersonaConnectionLocked(c)) ?? []; |
| 910 | if (newConnection && newConnection.id) { | 938 | if (newConnection && newConnection.id) { |
| @@ -1249,7 +1277,7 @@ async function loadPersonaForCurrentChat() { | |||
| 1249 | } else { | 1277 | } else { |
| 1250 | chatPersona = await askForPersonaSelection(t`Select Persona`, | 1278 | chatPersona = await askForPersonaSelection(t`Select Persona`, |
| 1251 | t`Multiple personas are connected to this character.\nSelect a persona to use for this chat.`, | 1279 | t`Multiple personas are connected to this character.\nSelect a persona to use for this chat.`, |
| 1252 | connectedPersonas, { highlightPersonas: true }); | 1280 | connectedPersonas, { highlightPersonas: true, targetedChar: getCurrentConnectionObj() }); |
| 1253 | } | 1281 | } |
| 1254 | } | 1282 | } |
| 1255 | 1283 | ||
| @@ -1303,6 +1331,20 @@ export function getConnectedPersonas(characterKey = undefined) { | |||
| 1303 | return connectedPersonas; | 1331 | return connectedPersonas; |
| 1304 | } | 1332 | } |
| 1305 | 1333 | ||
| 1334 | /** | ||
| 1335 | * Retrieves the current connection object based on whether the current chat is with a char or a group. | ||
| 1336 | * | ||
| 1337 | * @returns {PersonaConnection} An object representing the current connection | ||
| 1338 | */ | ||
| 1339 | |||
| 1340 | export function getCurrentConnectionObj() { | ||
| 1341 | if (menu_type === 'group_edit') | ||
| 1342 | return { type: 'group', id: selected_group }; | ||
| 1343 | if (menu_type == 'character_edit') | ||
| 1344 | return { type: 'character', id: characters[this_chid]?.avatar }; | ||
| 1345 | return null; | ||
| 1346 | } | ||
| 1347 | |||
| 1306 | function onBackupPersonas() { | 1348 | function onBackupPersonas() { |
| 1307 | const timestamp = new Date().toISOString().split('T')[0].replace(/-/g, ''); | 1349 | const timestamp = new Date().toISOString().split('T')[0].replace(/-/g, ''); |
| 1308 | const filename = `personas_${timestamp}.json`; | 1350 | const filename = `personas_${timestamp}.json`; |