Merge pull request #2351 from Wolfsblvt/rename-char-command

/rename-char slash command
This commit is contained in:
Cohee 2024-06-05 22:53:54 +03:00 committed by GitHub
commit 179a099954
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 101 additions and 47 deletions

View File

@ -5431,70 +5431,95 @@ export function setSendButtonState(value) {
is_send_press = value; is_send_press = value;
} }
async function renameCharacter() { export async function renameCharacter(name = null, { silent = false, renameChats = null } = {}) {
if (!name && silent) {
toastr.warning('No character name provided.', 'Rename Character');
return false;
}
if (this_chid === undefined) {
toastr.warning('No character selected.', 'Rename Character');
return false;
}
const oldAvatar = characters[this_chid].avatar; const oldAvatar = characters[this_chid].avatar;
const newValue = await callPopup('<h3>New name:</h3>', 'input', characters[this_chid].name); const newValue = name || await callPopup('<h3>New name:</h3>', 'input', characters[this_chid].name);
if (newValue && newValue !== characters[this_chid].name) { if (!newValue) {
const body = JSON.stringify({ avatar_url: oldAvatar, new_name: newValue }); toastr.warning('No character name provided.', 'Rename Character');
const response = await fetch('/api/characters/rename', { return false;
method: 'POST', }
headers: getRequestHeaders(), if (newValue === characters[this_chid].name) {
body, toastr.info('Same character name provided, so name did not change.', 'Rename Character');
}); return false;
}
try { const body = JSON.stringify({ avatar_url: oldAvatar, new_name: newValue });
if (response.ok) { const response = await fetch('/api/characters/rename', {
const data = await response.json(); method: 'POST',
const newAvatar = data.avatar; headers: getRequestHeaders(),
body,
});
// Replace tags list try {
renameTagKey(oldAvatar, newAvatar); if (response.ok) {
const data = await response.json();
const newAvatar = data.avatar;
// Reload characters list // Replace tags list
await getCharacters(); renameTagKey(oldAvatar, newAvatar);
// Find newly renamed character // Reload characters list
const newChId = characters.findIndex(c => c.avatar == data.avatar); await getCharacters();
if (newChId !== -1) { // Find newly renamed character
// Select the character after the renaming const newChId = characters.findIndex(c => c.avatar == data.avatar);
this_chid = -1;
await selectCharacterById(String(newChId));
// Async delay to update UI if (newChId !== -1) {
await delay(1); // Select the character after the renaming
this_chid = -1;
await selectCharacterById(String(newChId));
if (this_chid === -1) { // Async delay to update UI
throw new Error('New character not selected'); await delay(1);
}
// Also rename as a group member if (this_chid === -1) {
await renameGroupMember(oldAvatar, newAvatar, newValue); throw new Error('New character not selected');
const renamePastChatsConfirm = await callPopup(`<h3>Character renamed!</h3>
<p>Past chats will still contain the old character name. Would you like to update the character name in previous chats as well?</p>
<i><b>Sprites folder (if any) should be renamed manually.</b></i>`, 'confirm');
if (renamePastChatsConfirm) {
await renamePastChats(newAvatar, newValue);
await reloadCurrentChat();
toastr.success('Character renamed and past chats updated!');
}
} }
else {
throw new Error('Newly renamed character was lost?'); // Also rename as a group member
await renameGroupMember(oldAvatar, newAvatar, newValue);
const renamePastChatsConfirm = renameChats !== null ? renameChats
: silent ? false : await callPopup(`<h3>Character renamed!</h3>
<p>Past chats will still contain the old character name. Would you like to update the character name in previous chats as well?</p>
<i><b>Sprites folder (if any) should be renamed manually.</b></i>`, 'confirm');
if (renamePastChatsConfirm) {
await renamePastChats(newAvatar, newValue);
await reloadCurrentChat();
toastr.success('Character renamed and past chats updated!', 'Rename Character');
} else {
toastr.success('Character renamed!', 'Rename Character');
} }
} }
else { else {
throw new Error('Could not rename the character'); throw new Error('Newly renamed character was lost?');
} }
} }
catch { else {
// Reloading to prevent data corruption throw new Error('Could not rename the character');
await callPopup('Something went wrong. The page will be reloaded.', 'text');
location.reload();
} }
} }
catch (error) {
// Reloading to prevent data corruption
if (!silent) await callPopup('Something went wrong. The page will be reloaded.', 'text');
else toastr.error('Something went wrong. The page will be reloaded.', 'Rename Character');
console.log('Renaming character error:', error);
location.reload();
return false;
}
return true;
} }
async function renamePastChats(newAvatar, newValue) { async function renamePastChats(newAvatar, newValue) {

View File

@ -23,6 +23,7 @@ import {
name2, name2,
reloadCurrentChat, reloadCurrentChat,
removeMacros, removeMacros,
renameCharacter,
saveChatConditional, saveChatConditional,
sendMessageAsUser, sendMessageAsUser,
sendSystemMessage, sendSystemMessage,
@ -323,6 +324,29 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
helpString: 'Opens up a chat with the character or group by its name', helpString: 'Opens up a chat with the character or group by its name',
aliases: ['char'], aliases: ['char'],
})); }));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'rename-char',
/** @param {{silent: string, chats: string}} options @param {string} name */
callback: async ({ silent = 'true', chats = null }, name) => {
const renamed = await renameCharacter(name, { silent: isTrueBoolean(silent), renameChats: chats !== null ? isTrueBoolean(chats) : null });
return String(renamed);
},
returns: 'true/false - Whether the rename was successful',
namedArgumentList: [
new SlashCommandNamedArgument(
'silent', 'Hide any blocking popups. (if false, the name is optional. If not supplied, a popup asking for it will appear)', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true',
),
new SlashCommandNamedArgument(
'chats', 'Rename char in all previous chats', [ARGUMENT_TYPE.BOOLEAN], false, false, '<null>',
),
],
unnamedArgumentList: [
new SlashCommandArgument(
'new char name', [ARGUMENT_TYPE.STRING], true,
),
],
helpString: 'Renames the current character.',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'sysgen', name: 'sysgen',
callback: generateSystemMessage, callback: generateSystemMessage,

View File

@ -17,6 +17,11 @@ import { SlashCommandScope } from './SlashCommandScope.js';
* }} NamedArguments * }} NamedArguments
*/ */
/**
* Alternative object for local JSDocs, where you don't need existing pipe, scope, etc. arguments
* @typedef {{[id:string]:string|SlashCommandClosure}} NamedArgumentsCapture
*/
/** /**
* @typedef {string|SlashCommandClosure|(string|SlashCommandClosure)[]} UnnamedArguments * @typedef {string|SlashCommandClosure|(string|SlashCommandClosure)[]} UnnamedArguments
*/ */
@ -28,7 +33,7 @@ export class SlashCommand {
* Creates a SlashCommand from a properties object. * Creates a SlashCommand from a properties object.
* @param {Object} props * @param {Object} props
* @param {string} [props.name] * @param {string} [props.name]
* @param {(namedArguments:NamedArguments, unnamedArguments:string|SlashCommandClosure|(string|SlashCommandClosure)[])=>string|SlashCommandClosure|void|Promise<string|SlashCommandClosure|void>} [props.callback] * @param {(namedArguments:NamedArguments|NamedArgumentsCapture, unnamedArguments:string|SlashCommandClosure|(string|SlashCommandClosure)[])=>string|SlashCommandClosure|void|Promise<string|SlashCommandClosure|void>} [props.callback]
* @param {string} [props.helpString] * @param {string} [props.helpString]
* @param {boolean} [props.splitUnnamedArgument] * @param {boolean} [props.splitUnnamedArgument]
* @param {string[]} [props.aliases] * @param {string[]} [props.aliases]