Show connected characters in persona panel - Print list of connected characters in persona panel - Fix smaller bugs with missing connections in persona description

255e75c6cf9d4fdd5ebf00320ac33a445818bafd

Wolfsblvt <wolfsblvt@gmail.com>

3 files changed, +41 -4Ignore whitespace
public/index.html+3 -1
@@ -4976,7 +4976,9 @@
4976 <div data-i18n="Character">Character</div>4976 <div data-i18n="Character">Character</div>
4977 </div>4977 </div>
4978 </div>4978 </div>
4979 <div id="persona_connections_list" class="text_muted m-b-1" data-i18n="persona_no_connections">[No connections]</div>4979 <div id="persona_connections_list" class="text_muted m-b-1 avatars_inline flex-container scroll-reset-container expander" data-i18n="persona_no_connections">
4980 [No connections]
4981 </div>
4980 </div>4982 </div>
49814983
4982 <div class="persona_management_global_settings">4984 <div class="persona_management_global_settings">
public/script.js+2 -0
@@ -232,6 +232,7 @@ import {
232 initPersonas,232 initPersonas,
233 setPersonaDescription,233 setPersonaDescription,
234 initUserAvatar,234 initUserAvatar,
235 updatePersonaConnectionsAvatarList,
235} from './scripts/personas.js';236} from './scripts/personas.js';
236import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';237import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';
237import { hideLoader, showLoader } from './scripts/loader.js';238import { hideLoader, showLoader } from './scripts/loader.js';
@@ -1537,6 +1538,7 @@ export async function printCharacters(fullRefresh = false) {
1537 });1538 });
15381539
1539 favsToHotswap();1540 favsToHotswap();
1541 updatePersonaConnectionsAvatarList();
1540}1542}
15411543
1542/** Checks the state of the current search, and adds/removes the search sorting option accordingly */1544/** Checks the state of the current search, and adds/removes the search sorting option accordingly */
public/scripts/personas.js+36 -3
@@ -1,4 +1,6 @@
1import {1import {
2 buildAvatarList,
3 characterToEntity,
2 characters,4 characters,
3 chat,5 chat,
4 chat_metadata,6 chat_metadata,
@@ -7,6 +9,7 @@ import {
7 event_types,9 event_types,
8 getRequestHeaders,10 getRequestHeaders,
9 getThumbnailUrl,11 getThumbnailUrl,
12 groupToEntity,
10 menu_type,13 menu_type,
11 name1,14 name1,
12 name2,15 name2,
@@ -19,10 +22,10 @@ import {
19} from '../script.js';22} from '../script.js';
20import { persona_description_positions, power_user } from './power-user.js';23import { persona_description_positions, power_user } from './power-user.js';
21import { getTokenCountAsync } from './tokenizers.js';24import { getTokenCountAsync } from './tokenizers.js';
22import { PAGINATION_TEMPLATE, debounce, delay, download, ensureImageFormatSupported, flashHighlight, getBase64Async, parseJsonFile } from './utils.js';25import { PAGINATION_TEMPLATE, debounce, delay, download, ensureImageFormatSupported, flashHighlight, getBase64Async, getCharIndex, parseJsonFile } from './utils.js';
23import { debounce_timeout } from './constants.js';26import { debounce_timeout } from './constants.js';
24import { FILTER_TYPES, FilterHelper } from './filters.js';27import { FILTER_TYPES, FilterHelper } from './filters.js';
25import { selected_group } from './group-chats.js';28import { groups, selected_group } from './group-chats.js';
26import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';29import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
27import { t } from './i18n.js';30import { t } from './i18n.js';
28import { openWorldInfoEditor, world_names } from './world-info.js';31import { openWorldInfoEditor, world_names } from './world-info.js';
@@ -477,6 +480,34 @@ export function setPersonaDescription() {
477 .prop('selected', String(true));480 .prop('selected', String(true));
478 $('#persona_lore_button').toggleClass('world_set', !!power_user.persona_description_lorebook);481 $('#persona_lore_button').toggleClass('world_set', !!power_user.persona_description_lorebook);
479 countPersonaDescriptionTokens();482 countPersonaDescriptionTokens();
483
484 updatePersonaLockIcons();
485 updatePersonaConnectionsAvatarList();
486}
487
488/**
489 * Displays avatar connections for the current persona.
490 * Converts connections to entities and populates the avatar list. Shows a message if no connections are found.
491 */
492export function updatePersonaConnectionsAvatarList() {
493 /** @type {PersonaConnection[]} */
494 const connections = power_user.persona_descriptions[user_avatar]?.connections ?? [];
495 const entities = connections.map(connection => {
496 if (connection.type === 'character') {
497 const character = characters.find(c => c.avatar === connection.id);
498 if (character) return characterToEntity(character, getCharIndex(character));
499 }
500 if (connection.type === 'group') {
501 const group = groups.find(g => g.id === connection.id);
502 if (group) return groupToEntity(group);
503 }
504 return undefined;
505 }).filter(entity => entity?.item !== undefined);
506
507 if (entities.length)
508 buildAvatarList($('#persona_connections_list'), entities);
509 else
510 $('#persona_connections_list').text('[No connections]');
480}511}
481512
482export function autoSelectPersona(name) {513export function autoSelectPersona(name) {
@@ -694,6 +725,7 @@ async function unlockPersona(type = 'chat') {
694 console.log(`Unlocking persona ${user_avatar} from this character ${name2}`);725 console.log(`Unlocking persona ${user_avatar} from this character ${name2}`);
695 power_user.persona_descriptions[user_avatar].connections = connections.filter(c => !isPersonaConnectionLocked(c));726 power_user.persona_descriptions[user_avatar].connections = connections.filter(c => !isPersonaConnectionLocked(c));
696 saveSettingsDebounced();727 saveSettingsDebounced();
728 updatePersonaConnectionsAvatarList();
697 if (power_user.persona_show_notifications) {729 if (power_user.persona_show_notifications) {
698 toastr.info(t`User persona ${name1} is now unlocked from character ${name2}. Click the "Lock" again to revert.`, t`Persona unlocked`);730 toastr.info(t`User persona ${name1} is now unlocked from character ${name2}. Click the "Lock" again to revert.`, t`Persona unlocked`);
699 }731 }
@@ -756,6 +788,7 @@ async function lockPersona(type = 'chat') {
756 console.log(`Locking persona ${user_avatar} to this character ${name2}`);788 console.log(`Locking persona ${user_avatar} to this character ${name2}`);
757 power_user.persona_descriptions[user_avatar].connections = [...connections, newConnection];789 power_user.persona_descriptions[user_avatar].connections = [...connections, newConnection];
758 saveSettingsDebounced();790 saveSettingsDebounced();
791 updatePersonaConnectionsAvatarList();
759 if (power_user.persona_show_notifications) {792 if (power_user.persona_show_notifications) {
760 toastr.success(t`User persona ${name1} is locked to character ${name2}`);793 toastr.success(t`User persona ${name1} is locked to character ${name2}`);
761 }794 }
@@ -1026,7 +1059,7 @@ function updatePersonaLockIcons() {
10261059
1027 /** @type {PersonaConnection[]} */1060 /** @type {PersonaConnection[]} */
1028 const connections = power_user.persona_descriptions[user_avatar]?.connections;1061 const connections = power_user.persona_descriptions[user_avatar]?.connections;
1029 const hasCharLock = !!connections.some(c =>1062 const hasCharLock = !!connections?.some(c =>
1030 (menu_type === 'character_edit' && c.type === 'character' && c.id === characters[this_chid]?.avatar)1063 (menu_type === 'character_edit' && c.type === 'character' && c.id === characters[this_chid]?.avatar)
1031 || (menu_type === 'group_edit' && c.type === 'group' && c.id === selected_group));1064 || (menu_type === 'group_edit' && c.type === 'group' && c.id === selected_group));
1032 $('#lock_persona_to_char').toggleClass('locked', hasCharLock);1065 $('#lock_persona_to_char').toggleClass('locked', hasCharLock);