Merge branch 'staging' into fix/raw-quotes
| @@ -36,10 +36,10 @@ jobs: | |||
| 36 | for ISSUE in $(echo $issues | jq -r '.[]'); do | 36 | for ISSUE in $(echo $issues | jq -r '.[]'); do |
| 37 | if [ "${{ github.ref }}" == "refs/heads/staging" ]; then | 37 | if [ "${{ github.ref }}" == "refs/heads/staging" ]; then |
| 38 | LABEL="✅ Done (staging)" | 38 | LABEL="✅ Done (staging)" |
| 39 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL" | 39 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL" --remove-label "🧑💻 In Progress" |
| 40 | elif [ "${{ github.ref }}" == "refs/heads/release" ]; then | 40 | elif [ "${{ github.ref }}" == "refs/heads/release" ]; then |
| 41 | LABEL="✅ Done" | 41 | LABEL="✅ Done" |
| 42 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL" | 42 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL" --remove-label "🧑💻 In Progress" |
| 43 | fi | 43 | fi |
| 44 | echo "Added label '$LABEL' to issue #$ISSUE" | 44 | echo "Added label '$LABEL' (and removed '🧑💻 In Progress' if present) in issue #$ISSUE" |
| 45 | done | 45 | done |
| @@ -262,6 +262,6 @@ jobs: | |||
| 262 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | 262 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 263 | run: | | 263 | run: | |
| 264 | for ISSUE in $(echo $final_issues | jq -r '.[]'); do | 264 | for ISSUE in $(echo $final_issues | jq -r '.[]'); do |
| 265 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "✅ Done (staging)" | 265 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "✅ Done (staging)" --remove-label "🧑💻 In Progress" |
| 266 | echo "Added label '✅ Done (staging)' to issue #$ISSUE" | 266 | echo "Added label '✅ Done (staging)' (and removed '🧑💻 In Progress' if present) in issue #$ISSUE" |
| 267 | done | 267 | done |
| @@ -1,6 +1,6 @@ | |||
| 1 | 'use strict'; | 1 | 'use strict'; |
| 2 | 2 | ||
| 3 | import { DOMPurify, Popper } from '../lib.js'; | 3 | import { DOMPurify } from '../lib.js'; |
| 4 | 4 | ||
| 5 | import { event_types, eventSource, is_send_press, main_api, substituteParams } from '../script.js'; | 5 | import { event_types, eventSource, is_send_press, main_api, substituteParams } from '../script.js'; |
| 6 | import { is_group_generating } from './group-chats.js'; | 6 | import { is_group_generating } from './group-chats.js'; |
| @@ -1440,36 +1440,8 @@ class PromptManager { | |||
| 1440 | footerDiv.querySelector('select').selectedIndex = selectedPromptIndex; | 1440 | footerDiv.querySelector('select').selectedIndex = selectedPromptIndex; |
| 1441 | 1441 | ||
| 1442 | // Add prompt export dialogue and options | 1442 | // Add prompt export dialogue and options |
| 1443 | |||
| 1444 | const exportForCharacter = await renderTemplateAsync('promptManagerExportForCharacter'); | ||
| 1445 | const exportPopup = await renderTemplateAsync('promptManagerExportPopup', { isGlobalStrategy: 'global' === this.configuration.promptOrder.strategy, exportForCharacter }); | ||
| 1446 | rangeBlockDiv.insertAdjacentHTML('beforeend', exportPopup); | ||
| 1447 | |||
| 1448 | // Destroy previous popper instance if it exists | ||
| 1449 | if (this.exportPopper) { | ||
| 1450 | this.exportPopper.destroy(); | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | this.exportPopper = Popper.createPopper( | ||
| 1454 | document.getElementById('prompt-manager-export'), | ||
| 1455 | document.getElementById('prompt-manager-export-format-popup'), | ||
| 1456 | { placement: 'bottom' }, | ||
| 1457 | ); | ||
| 1458 | |||
| 1459 | const showExportSelection = () => { | ||
| 1460 | const popup = document.getElementById('prompt-manager-export-format-popup'); | ||
| 1461 | const show = popup.hasAttribute('data-show'); | ||
| 1462 | |||
| 1463 | if (show) popup.removeAttribute('data-show'); | ||
| 1464 | else popup.setAttribute('data-show', ''); | ||
| 1465 | |||
| 1466 | this.exportPopper.update(); | ||
| 1467 | }; | ||
| 1468 | |||
| 1469 | footerDiv.querySelector('#prompt-manager-import').addEventListener('click', this.handleImport); | 1443 | footerDiv.querySelector('#prompt-manager-import').addEventListener('click', this.handleImport); |
| 1470 | footerDiv.querySelector('#prompt-manager-export').addEventListener('click', showExportSelection); | 1444 | footerDiv.querySelector('#prompt-manager-export').addEventListener('click', this.handleFullExport); |
| 1471 | rangeBlockDiv.querySelector('.export-promptmanager-prompts-full').addEventListener('click', this.handleFullExport); | ||
| 1472 | rangeBlockDiv.querySelector('.export-promptmanager-prompts-character')?.addEventListener('click', this.handleCharacterExport); | ||
| 1473 | } | 1445 | } |
| 1474 | } | 1446 | } |
| 1475 | 1447 | ||
| @@ -111,6 +111,7 @@ export function setUserAvatar(imgfile, { toastPersonaNameChange = true, navigate | |||
| 111 | reloadUserAvatar(); | 111 | reloadUserAvatar(); |
| 112 | updatePersonaUIStates({ navigateToCurrent: navigateToCurrent }); | 112 | updatePersonaUIStates({ navigateToCurrent: navigateToCurrent }); |
| 113 | selectCurrentPersona({ toastPersonaNameChange: toastPersonaNameChange }); | 113 | selectCurrentPersona({ toastPersonaNameChange: toastPersonaNameChange }); |
| 114 | retriggerFirstMessageOnEmptyChat(); | ||
| 114 | saveSettingsDebounced(); | 115 | saveSettingsDebounced(); |
| 115 | $('.zoomed_avatar[forchar]').remove(); | 116 | $('.zoomed_avatar[forchar]').remove(); |
| 116 | } | 117 | } |
| @@ -465,7 +466,7 @@ export function initPersona(avatarId, personaName, personaDescription) { | |||
| 465 | * @returns {Promise<boolean>} A promise that resolves to true if the character was converted, false otherwise. | 466 | * @returns {Promise<boolean>} A promise that resolves to true if the character was converted, false otherwise. |
| 466 | */ | 467 | */ |
| 467 | export async function convertCharacterToPersona(characterId = null) { | 468 | export async function convertCharacterToPersona(characterId = null) { |
| 468 | if (null === characterId) characterId = this_chid; | 469 | if (null === characterId) characterId = Number(this_chid); |
| 469 | 470 | ||
| 470 | const avatarUrl = characters[characterId]?.avatar; | 471 | const avatarUrl = characters[characterId]?.avatar; |
| 471 | if (!avatarUrl) { | 472 | if (!avatarUrl) { |
| @@ -1243,7 +1244,7 @@ function getPersonaStates(avatarId) { | |||
| 1243 | /** @type {PersonaConnection[]} */ | 1244 | /** @type {PersonaConnection[]} */ |
| 1244 | const connections = power_user.persona_descriptions[avatarId]?.connections; | 1245 | const connections = power_user.persona_descriptions[avatarId]?.connections; |
| 1245 | const hasCharLock = !!connections?.some(c => | 1246 | const hasCharLock = !!connections?.some(c => |
| 1246 | (!selected_group && c.type === 'character' && c.id === characters[this_chid]?.avatar) | 1247 | (!selected_group && c.type === 'character' && c.id === characters[Number(this_chid)]?.avatar) |
| 1247 | || (selected_group && c.type === 'group' && c.id === selected_group)); | 1248 | || (selected_group && c.type === 'group' && c.id === selected_group)); |
| 1248 | 1249 | ||
| 1249 | return { | 1250 | return { |
| @@ -1481,7 +1482,7 @@ async function loadPersonaForCurrentChat({ doRender = false } = {}) { | |||
| 1481 | * @returns {string[]} - An array of persona keys that are connected to the given character key | 1482 | * @returns {string[]} - An array of persona keys that are connected to the given character key |
| 1482 | */ | 1483 | */ |
| 1483 | export function getConnectedPersonas(characterKey = undefined) { | 1484 | export function getConnectedPersonas(characterKey = undefined) { |
| 1484 | characterKey ??= selected_group || characters[this_chid]?.avatar; | 1485 | characterKey ??= selected_group || characters[Number(this_chid)]?.avatar; |
| 1485 | const connectedPersonas = Object.entries(power_user.persona_descriptions) | 1486 | const connectedPersonas = Object.entries(power_user.persona_descriptions) |
| 1486 | .filter(([_, desc]) => desc.connections?.some(conn => conn.type === 'character' && conn.id === characterKey)) | 1487 | .filter(([_, desc]) => desc.connections?.some(conn => conn.type === 'character' && conn.id === characterKey)) |
| 1487 | .map(([key, _]) => key); | 1488 | .map(([key, _]) => key); |
| @@ -1513,7 +1514,7 @@ export async function showCharConnections() { | |||
| 1513 | console.log(`Unlocking persona ${personaId} from current character ${name2}`); | 1514 | console.log(`Unlocking persona ${personaId} from current character ${name2}`); |
| 1514 | power_user.persona_descriptions[personaId].connections = connections.filter(c => { | 1515 | power_user.persona_descriptions[personaId].connections = connections.filter(c => { |
| 1515 | if (menu_type == 'group_edit' && c.type == 'group' && c.id == selected_group) return false; | 1516 | if (menu_type == 'group_edit' && c.type == 'group' && c.id == selected_group) return false; |
| 1516 | else if (c.type == 'character' && c.id == characters[this_chid]?.avatar) return false; | 1517 | else if (c.type == 'character' && c.id == characters[Number(this_chid)]?.avatar) return false; |
| 1517 | return true; | 1518 | return true; |
| 1518 | }); | 1519 | }); |
| 1519 | saveSettingsDebounced(); | 1520 | saveSettingsDebounced(); |
| @@ -1545,8 +1546,8 @@ export async function showCharConnections() { | |||
| 1545 | export function getCurrentConnectionObj() { | 1546 | export function getCurrentConnectionObj() { |
| 1546 | if (selected_group) | 1547 | if (selected_group) |
| 1547 | return { type: 'group', id: selected_group }; | 1548 | return { type: 'group', id: selected_group }; |
| 1548 | if (characters[this_chid]?.avatar) | 1549 | if (characters[Number(this_chid)]?.avatar) |
| 1549 | return { type: 'character', id: characters[this_chid]?.avatar }; | 1550 | return { type: 'character', id: characters[Number(this_chid)]?.avatar }; |
| 1550 | return null; | 1551 | return null; |
| 1551 | } | 1552 | } |
| 1552 | 1553 | ||
| @@ -1664,7 +1665,7 @@ async function syncUserNameToPersona() { | |||
| 1664 | * Only works if only the first message is present, and not in group mode. | 1665 | * Only works if only the first message is present, and not in group mode. |
| 1665 | */ | 1666 | */ |
| 1666 | export function retriggerFirstMessageOnEmptyChat() { | 1667 | export function retriggerFirstMessageOnEmptyChat() { |
| 1667 | if (this_chid >= 0 && !selected_group && chat.length === 1) { | 1668 | if (Number(this_chid) >= 0 && !selected_group && chat.length === 1) { |
| 1668 | $('#firstmessage_textarea').trigger('input'); | 1669 | $('#firstmessage_textarea').trigger('input'); |
| 1669 | } | 1670 | } |
| 1670 | } | 1671 | } |
| @@ -1782,7 +1783,6 @@ function setNameCallback({ mode = 'all' }, name) { | |||
| 1782 | if (!persona) persona = Object.entries(power_user.personas).find(([_, personaName]) => personaName.toLowerCase() === name.toLowerCase())?.[1]; | 1783 | if (!persona) persona = Object.entries(power_user.personas).find(([_, personaName]) => personaName.toLowerCase() === name.toLowerCase())?.[1]; |
| 1783 | if (persona) { | 1784 | if (persona) { |
| 1784 | autoSelectPersona(persona); | 1785 | autoSelectPersona(persona); |
| 1785 | retriggerFirstMessageOnEmptyChat(); | ||
| 1786 | return ''; | 1786 | return ''; |
| 1787 | } else if (mode === 'lookup') { | 1787 | } else if (mode === 'lookup') { |
| 1788 | toastr.warning(`Persona ${name} not found`); | 1788 | toastr.warning(`Persona ${name} not found`); |
| @@ -1793,7 +1793,6 @@ function setNameCallback({ mode = 'all' }, name) { | |||
| 1793 | if (['temp', 'all'].includes(mode)) { | 1793 | if (['temp', 'all'].includes(mode)) { |
| 1794 | // Otherwise, set just the name | 1794 | // Otherwise, set just the name |
| 1795 | setUserName(name); //this prevented quickReply usage | 1795 | setUserName(name); //this prevented quickReply usage |
| 1796 | retriggerFirstMessageOnEmptyChat(); | ||
| 1797 | } | 1796 | } |
| 1798 | 1797 | ||
| 1799 | return ''; | 1798 | return ''; |
| @@ -1944,9 +1943,6 @@ export async function initPersonas() { | |||
| 1944 | $(document).on('click', '#user_avatar_block .avatar-container', function () { | 1943 | $(document).on('click', '#user_avatar_block .avatar-container', function () { |
| 1945 | const imgfile = $(this).attr('data-avatar-id'); | 1944 | const imgfile = $(this).attr('data-avatar-id'); |
| 1946 | setUserAvatar(imgfile); | 1945 | setUserAvatar(imgfile); |
| 1947 | |||
| 1948 | // force firstMes {{user}} update on persona switch | ||
| 1949 | retriggerFirstMessageOnEmptyChat(); | ||
| 1950 | }); | 1946 | }); |
| 1951 | 1947 | ||
| 1952 | $('#persona_rename_button').on('click', () => renamePersona(user_avatar)); | 1948 | $('#persona_rename_button').on('click', () => renamePersona(user_avatar)); |
| @@ -1979,4 +1975,3 @@ export async function initPersonas() { | |||
| 1979 | eventSource.on(event_types.CHAT_CHANGED, loadPersonaForCurrentChat); | 1975 | eventSource.on(event_types.CHAT_CHANGED, loadPersonaForCurrentChat); |
| 1980 | switchPersonaGridView(); | 1976 | switchPersonaGridView(); |
| 1981 | } | 1977 | } |
| 1982 | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | <div class="row"> | ||
| 2 | <a class="export-promptmanager-prompts-character list-group-item" data-i18n="Export for character">Export for character</a> | ||
| 3 | <span class="tooltip fa-solid fa-info-circle" data-i18n="[title]Export prompts for this character, including their order." title="Export prompts for this character, including their order."></span> | ||
| 4 | </div> | ||
| @@ -1,12 +0,0 @@ | |||
| 1 | <div id="prompt-manager-export-format-popup" class="list-group"> | ||
| 2 | <div class="prompt-manager-export-format-popup-flex"> | ||
| 3 | <div class="row"> | ||
| 4 | <a class="export-promptmanager-prompts-full list-group-item" data-i18n="Export all">Export all</a> | ||
| 5 | <span class="tooltip fa-solid fa-info-circle" data-i18n="[title]Export all your prompts to a file" title="Export all your prompts to a file"></span> | ||
| 6 | </div> | ||
| 7 | {{#if isGlobalStrategy}} | ||
| 8 | {{else}} | ||
| 9 | {{{exportForCharacter}}} | ||
| 10 | {{/if}} | ||
| 11 | </div> | ||
| 12 | </div> | ||