Await for profiles loading before continuing

10ddf77948e0d93af1f14a8ea9801ce8a4b5d397

Cohee <18619528+Cohee1207@users.noreply.github.com>

2 files changed, +33 -7Showing whitespace changes
public/script.js+1 -0
@@ -462,6 +462,7 @@ export const event_types = {
462 LLM_FUNCTION_TOOL_CALL: 'llm_function_tool_call',462 LLM_FUNCTION_TOOL_CALL: 'llm_function_tool_call',
463 ONLINE_STATUS_CHANGED: 'online_status_changed',463 ONLINE_STATUS_CHANGED: 'online_status_changed',
464 IMAGE_SWIPED: 'image_swiped',464 IMAGE_SWIPED: 'image_swiped',
465 CONNECTION_PROFILE_LOADED: 'connection_profile_loaded',
465};466};
466467
467export const eventSource = new EventEmitter();468export const eventSource = new EventEmitter();
public/scripts/extensions/connection-manager/index.js+32 -7
@@ -1,13 +1,13 @@
1import { main_api, saveSettingsDebounced } from '../../../script.js';1import { event_types, eventSource, main_api, saveSettingsDebounced } from '../../../script.js';
2import { extension_settings, renderExtensionTemplateAsync } from '../../extensions.js';2import { extension_settings, renderExtensionTemplateAsync } from '../../extensions.js';
3import { callGenericPopup, Popup, POPUP_TYPE } from '../../popup.js';3import { callGenericPopup, Popup, POPUP_TYPE } from '../../popup.js';
4import { executeSlashCommandsWithOptions } from '../../slash-commands.js';4import { executeSlashCommandsWithOptions } from '../../slash-commands.js';
5import { SlashCommand } from '../../slash-commands/SlashCommand.js';5import { SlashCommand } from '../../slash-commands/SlashCommand.js';
6import { ARGUMENT_TYPE, SlashCommandArgument } from '../../slash-commands/SlashCommandArgument.js';6import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
7import { enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';7import { commonEnumProviders, enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
8import { enumTypes, SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';8import { enumTypes, SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';
9import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';9import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
10import { collapseSpaces, getUniqueName, uuidv4 } from '../../utils.js';10import { collapseSpaces, getUniqueName, isFalseBoolean, uuidv4 } from '../../utils.js';
1111
12const MODULE_NAME = 'connection-manager';12const MODULE_NAME = 'connection-manager';
13const NONE = '<None>';13const NONE = '<None>';
@@ -51,7 +51,7 @@ const FANCY_NAMES = {
5151
52/** @type {() => SlashCommandEnumValue[]} */52/** @type {() => SlashCommandEnumValue[]} */
53const profilesProvider = () => [53const profilesProvider = () => [
54 new SlashCommandEnumValue(NONE, NONE),54 new SlashCommandEnumValue(NONE),
55 ...extension_settings.connectionManager.profiles.map(p => new SlashCommandEnumValue(p.name, null, enumTypes.name, enumIcons.server)),55 ...extension_settings.connectionManager.profiles.map(p => new SlashCommandEnumValue(p.name, null, enumTypes.name, enumIcons.server)),
56];56];
5757
@@ -155,7 +155,7 @@ async function createConnectionProfile(forceName = null) {
155 return null;155 return null;
156 }156 }
157157
158 if (isNameTaken(name)) {158 if (isNameTaken(name) || name === NONE) {
159 toastr.error('A profile with the same name already exists.');159 toastr.error('A profile with the same name already exists.');
160 return null;160 return null;
161 }161 }
@@ -304,6 +304,8 @@ async function renderDetailsContent(details, detailsContent) {
304 profiles.addEventListener('change', async function () {304 profiles.addEventListener('change', async function () {
305 const selectedProfile = profiles.selectedOptions[0];305 const selectedProfile = profiles.selectedOptions[0];
306 if (!selectedProfile) {306 if (!selectedProfile) {
307 // Safety net for preventing the command getting stuck
308 await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, NONE);
307 return;309 return;
308 }310 }
309311
@@ -314,6 +316,7 @@ async function renderDetailsContent(details, detailsContent) {
314316
315 // None option selected317 // None option selected
316 if (!profileId) {318 if (!profileId) {
319 await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, NONE);
317 return;320 return;
318 }321 }
319322
@@ -325,6 +328,7 @@ async function renderDetailsContent(details, detailsContent) {
325 }328 }
326329
327 await applyConnectionProfile(profile);330 await applyConnectionProfile(profile);
331 await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name);
328 });332 });
329333
330 const reloadButton = document.getElementById('reload_connection_profile');334 const reloadButton = document.getElementById('reload_connection_profile');
@@ -337,6 +341,7 @@ async function renderDetailsContent(details, detailsContent) {
337 }341 }
338 await applyConnectionProfile(profile);342 await applyConnectionProfile(profile);
339 await renderDetailsContent(details, detailsContent);343 await renderDetailsContent(details, detailsContent);
344 await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name);
340 toastr.success('Connection profile reloaded', '', { timeOut: 1500 });345 toastr.success('Connection profile reloaded', '', { timeOut: 1500 });
341 });346 });
342347
@@ -351,6 +356,7 @@ async function renderDetailsContent(details, detailsContent) {
351 saveSettingsDebounced();356 saveSettingsDebounced();
352 renderConnectionProfiles(profiles);357 renderConnectionProfiles(profiles);
353 await renderDetailsContent(details, detailsContent);358 await renderDetailsContent(details, detailsContent);
359 await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name);
354 });360 });
355361
356 const updateButton = document.getElementById('update_connection_profile');362 const updateButton = document.getElementById('update_connection_profile');
@@ -364,6 +370,7 @@ async function renderDetailsContent(details, detailsContent) {
364 await updateConnectionProfile(profile);370 await updateConnectionProfile(profile);
365 await renderDetailsContent(details, detailsContent);371 await renderDetailsContent(details, detailsContent);
366 saveSettingsDebounced();372 saveSettingsDebounced();
373 await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name);
367 toastr.success('Connection profile updated', '', { timeOut: 1500 });374 toastr.success('Connection profile updated', '', { timeOut: 1500 });
368 });375 });
369376
@@ -372,6 +379,7 @@ async function renderDetailsContent(details, detailsContent) {
372 await deleteConnectionProfile();379 await deleteConnectionProfile();
373 renderConnectionProfiles(profiles);380 renderConnectionProfiles(profiles);
374 await renderDetailsContent(details, detailsContent);381 await renderDetailsContent(details, detailsContent);
382 await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, NONE);
375 });383 });
376384
377 /** @type {HTMLDetailsElement} */385 /** @type {HTMLDetailsElement} */
@@ -391,7 +399,17 @@ async function renderDetailsContent(details, detailsContent) {
391 isRequired: false,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 if (!value || typeof value !== 'string') {413 if (!value || typeof value !== 'string') {
396 const selectedProfile = extension_settings.connectionManager.selectedProfile;414 const selectedProfile = extension_settings.connectionManager.selectedProfile;
397 const profile = extension_settings.connectionManager.profiles.find(p => p.id === selectedProfile);415 const profile = extension_settings.connectionManager.profiles.find(p => p.id === selectedProfile);
@@ -413,9 +431,16 @@ async function renderDetailsContent(details, detailsContent) {
413 return '';431 return '';
414 }432 }
415433
434 const shouldAwait = !isFalseBoolean(String(args?.await));
435 const awaitPromise = new Promise((resolve) => eventSource.once(event_types.CONNECTION_PROFILE_LOADED, resolve));
436
416 profiles.selectedIndex = Array.from(profiles.options).findIndex(o => o.value === profile.id);437 profiles.selectedIndex = Array.from(profiles.options).findIndex(o => o.value === profile.id);
417 profiles.dispatchEvent(new Event('change'));438 profiles.dispatchEvent(new Event('change'));
418439
440 if (shouldAwait) {
441 await awaitPromise;
442 }
443
419 return profile.name;444 return profile.name;
420 },445 },
421 }));446 }));