summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Bofill <jesse_bofill@yahoo.com>2025-10-06 14:29:39 -0600
committerJesse Bofill <jesse_bofill@yahoo.com>2025-10-06 14:29:39 -0600
commit1ae6519209c9bf079d8dff80d5bceb5a847b08b1 (patch)
tree05daa08379fb895d5ac7f1c41ef87514803c56b6
parent65f1eb052de17f21144571d932281a0484f48dfd (diff)
downloaddecky-loader-1ae6519209c9bf079d8dff80d5bceb5a847b08b1.tar.gz
decky-loader-1ae6519209c9bf079d8dff80d5bceb5a847b08b1.zip
implement frontend diisable functions/ modal
-rw-r--r--frontend/src/components/modals/PluginDisablelModal.tsx46
-rw-r--r--frontend/src/components/settings/pages/plugin_list/index.tsx22
-rw-r--r--frontend/src/plugin-loader.tsx4
-rw-r--r--frontend/src/plugin.ts2
4 files changed, 72 insertions, 2 deletions
diff --git a/frontend/src/components/modals/PluginDisablelModal.tsx b/frontend/src/components/modals/PluginDisablelModal.tsx
new file mode 100644
index 00000000..89cda293
--- /dev/null
+++ b/frontend/src/components/modals/PluginDisablelModal.tsx
@@ -0,0 +1,46 @@
+import { ConfirmModal, Spinner } from '@decky/ui';
+import { FC, useState } from 'react';
+
+import { disablePlugin, uninstallPlugin } from '../../plugin';
+
+interface PluginUninstallModalProps {
+ name: string;
+ title: string;
+ buttonText: string;
+ description: string;
+ closeModal?(): void;
+}
+
+const PluginDisableModal: FC<PluginUninstallModalProps> = ({ name, title, buttonText, description, closeModal }) => {
+ const [disabling, setDisabling] = useState<boolean>(false);
+ return (
+ <ConfirmModal
+ closeModal={closeModal}
+ onOK={async () => {
+ setDisabling(true);
+ await disablePlugin(name);
+
+ //not sure about this yet
+
+ // uninstalling a plugin resets the hidden setting for it server-side
+ // we invalidate here so if you re-install it, you won't have an out-of-date hidden filter
+ await DeckyPluginLoader.frozenPluginsService.invalidate();
+ await DeckyPluginLoader.hiddenPluginsService.invalidate();
+ closeModal?.();
+ }}
+ bOKDisabled={disabling}
+ bCancelDisabled={disabling}
+ strTitle={
+ <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', width: '100%' }}>
+ {title}
+ {disabling && <Spinner width="24px" height="24px" style={{ marginLeft: 'auto' }} />}
+ </div>
+ }
+ strOKButtonText={buttonText}
+ >
+ {description}
+ </ConfirmModal>
+ );
+};
+
+export default PluginDisableModal;
diff --git a/frontend/src/components/settings/pages/plugin_list/index.tsx b/frontend/src/components/settings/pages/plugin_list/index.tsx
index e244b8a9..f13cbe2b 100644
--- a/frontend/src/components/settings/pages/plugin_list/index.tsx
+++ b/frontend/src/components/settings/pages/plugin_list/index.tsx
@@ -35,6 +35,7 @@ async function reinstallPlugin(pluginName: string, currentVersion?: string) {
type PluginTableData = PluginData & {
name: string;
+ disabled: boolean;
frozen: boolean;
onFreeze(): void;
onUnfreeze(): void;
@@ -54,7 +55,7 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginTableData> }
return null;
}
- const { name, update, version, onHide, onShow, hidden, onFreeze, onUnfreeze, frozen, isDeveloper } = props.entry.data;
+ const { name, update, version, onHide, onShow, hidden, onFreeze, onUnfreeze, frozen, isDeveloper, disabled } = props.entry.data;
const showCtxMenu = (e: MouseEvent | GamepadEvent) => {
showContextMenu(
@@ -82,6 +83,22 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginTableData> }
>
{t('PluginListIndex.uninstall')}
</MenuItem>
+ {disabled ? <MenuItem
+ onSelected={() =>
+ DeckyPluginLoader.disablePlugin(
+ name,
+ t('PluginLoader.plugin_disable.title', { name }),
+ t('PluginLoader.plugin_disable.button'),
+ t('PluginLoader.plugin_disable.desc', { name }),
+ )
+ }
+ >
+ {t('PluginListIndex.plugin_disable')}
+ </MenuItem> :
+ // implement enabler
+ <>
+ </>
+ }
{hidden ? (
<MenuItem onSelected={onShow}>{t('PluginListIndex.show')}</MenuItem>
) : (
@@ -147,7 +164,7 @@ type PluginData = {
};
export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) {
- const { installedPlugins, updates, pluginOrder, setPluginOrder, frozenPlugins, hiddenPlugins } = useDeckyState();
+ const { installedPlugins, disabled, updates, pluginOrder, setPluginOrder, frozenPlugins, hiddenPlugins } = useDeckyState();
const [_, setPluginOrderSetting] = useSetting<string[]>(
'pluginOrder',
@@ -174,6 +191,7 @@ export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) {
position: pluginOrder.indexOf(name),
data: {
name,
+ disabled: disabled.some(disabledPlugin => disabledPlugin.name === name),
frozen,
hidden,
isDeveloper,
diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx
index 9d74cbae..755c4460 100644
--- a/frontend/src/plugin-loader.tsx
+++ b/frontend/src/plugin-loader.tsx
@@ -341,6 +341,10 @@ class PluginLoader extends Logger {
showModal(<PluginUninstallModal name={name} title={title} buttonText={buttonText} description={description} />);
}
+ public disablePlugin(name: string, title: string, buttonText: string, description: string) {
+ showModal(<PluginUninstallModal name={name} title={title} buttonText={buttonText} description={description} />);
+ }
+
public hasPlugin(name: string) {
return Boolean(this.plugins.find((plugin) => plugin.name == name));
}
diff --git a/frontend/src/plugin.ts b/frontend/src/plugin.ts
index f53118b2..32d423d5 100644
--- a/frontend/src/plugin.ts
+++ b/frontend/src/plugin.ts
@@ -57,3 +57,5 @@ type installPluginsArgs = [
export let installPlugins = DeckyBackend.callable<installPluginsArgs>('utilities/install_plugins');
export let uninstallPlugin = DeckyBackend.callable<[name: string]>('utilities/uninstall_plugin');
+export let enablePlugin = DeckyBackend.callable<[name: string]>('utilities/enable_plugin');
+export let disablePlugin = DeckyBackend.callable<[name: string]>('utilities/disable_plugin');