Add /extension-toggle
| @@ -8,7 +8,7 @@ import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCom | ||
| 8 | 8 | import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; |
| 9 | 9 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 10 | 10 | import { renderTemplate, renderTemplateAsync } from './templates.js'; |
| 11 | 11 | import { equalsIgnoreCaseAndAccents, isFalseBoolean, isSubsetOf, isTrueBoolean, setValueByPath } from './utils.js'; |
| 12 | 12 | export { |
| 13 | 13 | getContext, |
| 14 | 14 | getApiUrl, |
| @@ -1050,33 +1050,50 @@ export async function openThirdPartyExtensionMenu(suggestUrl = '') { | ||
| 1050 | 1050 | } |
| 1051 | 1051 | |
| 1052 | 1052 | /** |
| 1053 | 1053 | * @param {boolean'enable' | 'disable' | 'toggle'} enableaction - WhetherThe toaction enableto orperform disableon the extension |
| 1054 | 1054 | * @returns {(args: {[key: string]: string | SlashCommandClosure}, extensionName: string | SlashCommandClosure) => Promise<string>} |
| 1055 | 1055 | */ |
| 1056 | 1056 | function getExtensionToggleCallbackgetExtensionActionCallback(enableaction) { |
| 1057 | 1057 | return async (args, extensionName) => { |
| 1058 | 1058 | if (args?.reload instanceof SlashCommandClosure) throw new Error('\'reload\' argument cannot be a closure.'); |
| 1059 | 1059 | if (typeof extensionName !== 'string') throw new Error('Extension name does only support string. Closures or arrays are not allowed.'); |
| 1060 | 1060 | if (!extensionName) { |
| 1061 | 1061 | toastr.warning(`Extension name must be provided as an argument to ${enable ? 'enable' : 'disable'action} this extension.`); |
| 1062 | 1062 | return ''; |
| 1063 | 1063 | } |
| 1064 | 1064 | |
| 1065 | 1065 | const reload = isTrueBoolean(args?.reload); |
| 1066 | - | |
| 1067 | 1066 | const internalExtensionName = extensionNames.find(x => equalsIgnoreCaseAndAccents(x, extensionName)); |
| 1068 | 1067 | if (!internalExtensionName) { |
| 1069 | 1068 | toastr.warning(`Extension ${extensionName} does not exist.`); |
| 1070 | 1069 | return ''; |
| 1071 | 1070 | } |
| 1072 | - if (enable === !extension_settings.disabledExtensions.includes(internalExtensionName)) { | |
| 1071 | + | |
| 1073 | - toastr.info(`Extension ${extensionName} is already ${enable ? 'enabled' : 'disabled'}.`); | |
| 1072 | + const isEnabled = !extension_settings.disabledExtensions.includes(internalExtensionName); | |
| 1073 | + | |
| 1074 | + if (action === 'enable' && isEnabled) { | |
| 1075 | + toastr.info(`Extension ${extensionName} is already enabled.`); | |
| 1074 | 1076 | return internalExtensionName; |
| 1075 | 1077 | } |
| 1076 | 1078 | |
| 1077 | - reload && toastr.info(`${enable ? 'Enabling' : 'Disabling'} extension ${extensionName} and reloading...`); | |
| 1079 | + if (action === 'disable' && !isEnabled) { | |
| 1078 | - await enableExtension(internalExtensionName, reload); | |
| 1080 | + toastr.info(`Extension ${extensionName} is already disabled.`); | |
| 1079 | - toastr.success(`Extension ${extensionName} ${enable ? 'enabled' : 'disabled'}.`); | |
| 1081 | + return internalExtensionName; | |
| 1082 | + } | |
| 1083 | + | |
| 1084 | + if (action === 'toggle') { | |
| 1085 | + action = isEnabled ? 'disable' : 'enable'; | |
| 1086 | + } | |
| 1087 | + | |
| 1088 | + reload && toastr.info(`${action.charAt(0).toUpperCase() + action.slice(1)}ing extension ${extensionName} and reloading...`); | |
| 1089 | + | |
| 1090 | + if (action === 'enable') { | |
| 1091 | + await enableExtension(internalExtensionName, reload); | |
| 1092 | + } else { | |
| 1093 | + await disableExtension(internalExtensionName, reload); | |
| 1094 | + } | |
| 1095 | + | |
| 1096 | + toastr.success(`Extension ${extensionName} ${action}d.`); | |
| 1080 | 1097 | |
| 1081 | 1098 | return internalExtensionName; |
| 1082 | 1099 | }; |
| @@ -1085,7 +1102,7 @@ function getExtensionToggleCallback(enable) { | ||
| 1085 | 1102 | function registerExtensionSlashCommands() { |
| 1086 | 1103 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1087 | 1104 | name: 'extension-enable', |
| 1088 | 1105 | callback: getExtensionToggleCallbackgetExtensionActionCallback(true'enable'), |
| 1089 | 1106 | namedArgumentList: [ |
| 1090 | 1107 | SlashCommandNamedArgument.fromProps({ |
| 1091 | 1108 | name: 'reload', |
| @@ -1125,7 +1142,7 @@ function registerExtensionSlashCommands() { | ||
| 1125 | 1142 | })); |
| 1126 | 1143 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1127 | 1144 | name: 'extension-disable', |
| 1128 | 1145 | callback: getExtensionToggleCallbackgetExtensionActionCallback(false'enable'), |
| 1129 | 1146 | namedArgumentList: [ |
| 1130 | 1147 | SlashCommandNamedArgument.fromProps({ |
| 1131 | 1148 | name: 'reload', |
| @@ -1163,6 +1180,64 @@ function registerExtensionSlashCommands() { | ||
| 1163 | 1180 | </div> |
| 1164 | 1181 | `, |
| 1165 | 1182 | })); |
| 1183 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1184 | + name: 'extension-toggle', | |
| 1185 | + callback: async (args, extensionName) => { | |
| 1186 | + if (args?.state instanceof SlashCommandClosure) throw new Error('\'state\' argument cannot be a closure.'); | |
| 1187 | + if (typeof extensionName !== 'string') throw new Error('Extension name does only support string. Closures or arrays are not allowed.'); | |
| 1188 | + | |
| 1189 | + const action = isTrueBoolean(args?.state) ? 'enable' : | |
| 1190 | + isFalseBoolean(args?.state) ? 'disable' : | |
| 1191 | + 'toggle'; | |
| 1192 | + | |
| 1193 | + return await getExtensionActionCallback(action)(args, extensionName); | |
| 1194 | + }, | |
| 1195 | + namedArgumentList: [ | |
| 1196 | + SlashCommandNamedArgument.fromProps({ | |
| 1197 | + name: 'reload', | |
| 1198 | + description: 'Whether to reload the page after toggling the extension', | |
| 1199 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 1200 | + defaultValue: 'true', | |
| 1201 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 1202 | + }), | |
| 1203 | + SlashCommandNamedArgument.fromProps({ | |
| 1204 | + name: 'state', | |
| 1205 | + description: 'Explicitly set the state of the extension (true to enable, false to disable). If not provided, the state will be toggled to the opposite of the current state.', | |
| 1206 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 1207 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 1208 | + }), | |
| 1209 | + ], | |
| 1210 | + unnamedArgumentList: [ | |
| 1211 | + SlashCommandArgument.fromProps({ | |
| 1212 | + description: 'Extension name', | |
| 1213 | + typeList: [ARGUMENT_TYPE.STRING], | |
| 1214 | + isRequired: true, | |
| 1215 | + enumProvider: () => extensionNames.map(name => new SlashCommandEnumValue(name)), | |
| 1216 | + forceEnum: true, | |
| 1217 | + }), | |
| 1218 | + ], | |
| 1219 | + helpString: ` | |
| 1220 | + <div> | |
| 1221 | + Toggles the state of a specified extension. | |
| 1222 | + </div> | |
| 1223 | + <div> | |
| 1224 | + By default, the page will be reloaded automatically, stopping any further commands.<br /> | |
| 1225 | + If <code>reload=false</code> named argument is passed, the page will not be reloaded, and the extension will stay in its current state until refreshed. | |
| 1226 | + The page either needs to be refreshed, or <code>/reload-page</code> has to be called. | |
| 1227 | + </div> | |
| 1228 | + <div> | |
| 1229 | + <strong>Example:</strong> | |
| 1230 | + <ul> | |
| 1231 | + <li> | |
| 1232 | + <pre><code class="language-stscript">/extension-toggle Summarize</code></pre> | |
| 1233 | + </li> | |
| 1234 | + <li> | |
| 1235 | + <pre><code class="language-stscript">/extension-toggle Summarize state=true</code></pre> | |
| 1236 | + </li> | |
| 1237 | + </ul> | |
| 1238 | + </div> | |
| 1239 | + `, | |
| 1240 | + })); | |
| 1166 | 1241 | |
| 1167 | 1242 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1168 | 1243 | name: 'reload-page', |