Await for profiles loading before continuing
| @@ -462,6 +462,7 @@ export const event_types = { | ||
| 462 | 462 | LLM_FUNCTION_TOOL_CALL: 'llm_function_tool_call', |
| 463 | 463 | ONLINE_STATUS_CHANGED: 'online_status_changed', |
| 464 | 464 | IMAGE_SWIPED: 'image_swiped', |
| 465 | + CONNECTION_PROFILE_LOADED: 'connection_profile_loaded', | |
| 465 | 466 | }; |
| 466 | 467 | |
| 467 | 468 | export const eventSource = new EventEmitter(); |
| @@ -1,13 +1,13 @@ | ||
| 1 | 1 | import { event_types, eventSource, main_api, saveSettingsDebounced } from '../../../script.js'; |
| 2 | 2 | import { extension_settings, renderExtensionTemplateAsync } from '../../extensions.js'; |
| 3 | 3 | import { callGenericPopup, Popup, POPUP_TYPE } from '../../popup.js'; |
| 4 | 4 | import { executeSlashCommandsWithOptions } from '../../slash-commands.js'; |
| 5 | 5 | import { SlashCommand } from '../../slash-commands/SlashCommand.js'; |
| 6 | 6 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js'; |
| 7 | 7 | import { commonEnumProviders, enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 8 | 8 | import { enumTypes, SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js'; |
| 9 | 9 | import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js'; |
| 10 | 10 | import { collapseSpaces, getUniqueName, isFalseBoolean, uuidv4 } from '../../utils.js'; |
| 11 | 11 | |
| 12 | 12 | const MODULE_NAME = 'connection-manager'; |
| 13 | 13 | const NONE = '<None>'; |
| @@ -51,7 +51,7 @@ const FANCY_NAMES = { | ||
| 51 | 51 | |
| 52 | 52 | /** @type {() => SlashCommandEnumValue[]} */ |
| 53 | 53 | const profilesProvider = () => [ |
| 54 | 54 | new SlashCommandEnumValue(NONE, NONE), |
| 55 | 55 | ...extension_settings.connectionManager.profiles.map(p => new SlashCommandEnumValue(p.name, null, enumTypes.name, enumIcons.server)), |
| 56 | 56 | ]; |
| 57 | 57 | |
| @@ -155,7 +155,7 @@ async function createConnectionProfile(forceName = null) { | ||
| 155 | 155 | return null; |
| 156 | 156 | } |
| 157 | 157 | |
| 158 | 158 | if (isNameTaken(name) || name === NONE) { |
| 159 | 159 | toastr.error('A profile with the same name already exists.'); |
| 160 | 160 | return null; |
| 161 | 161 | } |
| @@ -304,6 +304,8 @@ async function renderDetailsContent(details, detailsContent) { | ||
| 304 | 304 | profiles.addEventListener('change', async function () { |
| 305 | 305 | const selectedProfile = profiles.selectedOptions[0]; |
| 306 | 306 | if (!selectedProfile) { |
| 307 | + // Safety net for preventing the command getting stuck | |
| 308 | + await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, NONE); | |
| 307 | 309 | return; |
| 308 | 310 | } |
| 309 | 311 | |
| @@ -314,6 +316,7 @@ async function renderDetailsContent(details, detailsContent) { | ||
| 314 | 316 | |
| 315 | 317 | // None option selected |
| 316 | 318 | if (!profileId) { |
| 319 | + await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, NONE); | |
| 317 | 320 | return; |
| 318 | 321 | } |
| 319 | 322 | |
| @@ -325,6 +328,7 @@ async function renderDetailsContent(details, detailsContent) { | ||
| 325 | 328 | } |
| 326 | 329 | |
| 327 | 330 | await applyConnectionProfile(profile); |
| 331 | + await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name); | |
| 328 | 332 | }); |
| 329 | 333 | |
| 330 | 334 | const reloadButton = document.getElementById('reload_connection_profile'); |
| @@ -337,6 +341,7 @@ async function renderDetailsContent(details, detailsContent) { | ||
| 337 | 341 | } |
| 338 | 342 | await applyConnectionProfile(profile); |
| 339 | 343 | await renderDetailsContent(details, detailsContent); |
| 344 | + await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name); | |
| 340 | 345 | toastr.success('Connection profile reloaded', '', { timeOut: 1500 }); |
| 341 | 346 | }); |
| 342 | 347 | |
| @@ -351,6 +356,7 @@ async function renderDetailsContent(details, detailsContent) { | ||
| 351 | 356 | saveSettingsDebounced(); |
| 352 | 357 | renderConnectionProfiles(profiles); |
| 353 | 358 | await renderDetailsContent(details, detailsContent); |
| 359 | + await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name); | |
| 354 | 360 | }); |
| 355 | 361 | |
| 356 | 362 | const updateButton = document.getElementById('update_connection_profile'); |
| @@ -364,6 +370,7 @@ async function renderDetailsContent(details, detailsContent) { | ||
| 364 | 370 | await updateConnectionProfile(profile); |
| 365 | 371 | await renderDetailsContent(details, detailsContent); |
| 366 | 372 | saveSettingsDebounced(); |
| 373 | + await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name); | |
| 367 | 374 | toastr.success('Connection profile updated', '', { timeOut: 1500 }); |
| 368 | 375 | }); |
| 369 | 376 | |
| @@ -372,6 +379,7 @@ async function renderDetailsContent(details, detailsContent) { | ||
| 372 | 379 | await deleteConnectionProfile(); |
| 373 | 380 | renderConnectionProfiles(profiles); |
| 374 | 381 | await renderDetailsContent(details, detailsContent); |
| 382 | + await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, NONE); | |
| 375 | 383 | }); |
| 376 | 384 | |
| 377 | 385 | /** @type {HTMLDetailsElement} */ |
| @@ -391,7 +399,17 @@ async function renderDetailsContent(details, detailsContent) { | ||
| 391 | 399 | isRequired: false, |
| 392 | 400 | }), |
| 393 | 401 | ], |
| 394 | - callback: async (_args, value) => { | |
| 402 | + namedArgumentList: [ | |
| 403 | + SlashCommandNamedArgument.fromProps({ | |
| 404 | + name: 'await', | |
| 405 | + description: 'Wait for the connection profile to be applied before returning.', | |
| 406 | + isRequired: false, | |
| 407 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 408 | + defaultValue: 'true', | |
| 409 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 410 | + }), | |
| 411 | + ], | |
| 412 | + callback: async (args, value) => { | |
| 395 | 413 | if (!value || typeof value !== 'string') { |
| 396 | 414 | const selectedProfile = extension_settings.connectionManager.selectedProfile; |
| 397 | 415 | const profile = extension_settings.connectionManager.profiles.find(p => p.id === selectedProfile); |
| @@ -413,9 +431,16 @@ async function renderDetailsContent(details, detailsContent) { | ||
| 413 | 431 | return ''; |
| 414 | 432 | } |
| 415 | 433 | |
| 434 | + const shouldAwait = !isFalseBoolean(String(args?.await)); | |
| 435 | + const awaitPromise = new Promise((resolve) => eventSource.once(event_types.CONNECTION_PROFILE_LOADED, resolve)); | |
| 436 | + | |
| 416 | 437 | profiles.selectedIndex = Array.from(profiles.options).findIndex(o => o.value === profile.id); |
| 417 | 438 | profiles.dispatchEvent(new Event('change')); |
| 418 | 439 | |
| 440 | + if (shouldAwait) { | |
| 441 | + await awaitPromise; | |
| 442 | + } | |
| 443 | + | |
| 419 | 444 | return profile.name; |
| 420 | 445 | }, |
| 421 | 446 | })); |