Remove all connections button for the popups

9a79c6b1a4138c04864d2664a0f7078b76b9994a

Wolfsblvt <wolfsblvt@gmail.com>

2 files changed, +50 -6Ignore whitespace
public/script.js+2 -0
@@ -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';
240import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';241import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';
241import { hideLoader, showLoader } from './scripts/loader.js';242import { 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) => {
999910001
10000 const personaId = $(element).attr('data-pid');10002 const personaId = $(element).attr('data-pid');
public/scripts/personas.js+48 -6
@@ -561,9 +561,10 @@ export function updatePersonaConnectionsAvatarList() {
561 * @param {string} [options.okButton='None'] - The label for the OK button561 * @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-click562 * @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 chat563 * @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 made565 * @returns {Promise<string?>} - A promise that resolves to the selected persona id or null if no selection was made
565 */566 */
566export async function askForPersonaSelection(title, text, personas, { okButton = 'None', shiftClickHandler = undefined, highlightPersonas = false } = {}) {567export 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 else584 else
584 personaListBlock.textContent = '[No personas]';585 personaListBlock.textContent = t`[Currently no personas connected]`;
585586
586 const personasToHighlight = highlightPersonas instanceof Array ? highlightPersonas : (highlightPersonas ? getPersonasOfCurrentChat() : []);587 const personasToHighlight = highlightPersonas instanceof Array ? highlightPersonas : (highlightPersonas ? getPersonasOfCurrentChat() : []);
587588
@@ -605,7 +606,35 @@ export async function askForPersonaSelection(title, text, personas, { okButton =
605 }606 }
606 });607 });
607608
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 }
12551283
@@ -1303,6 +1331,20 @@ export function getConnectedPersonas(characterKey = undefined) {
1303 return connectedPersonas;1331 return connectedPersonas;
1304}1332}
13051333
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
1340export 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
1306function onBackupPersonas() {1348function 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`;