From 6f1527e4190d6dafb39082e6467ed35017b530e6 Mon Sep 17 00:00:00 2001 From: Andrew Moore Date: Sun, 28 Jan 2024 15:29:27 -0500 Subject: [PATCH] [Feature] Freeze updates for devs --- backend/locales/en-US.json | 2 + backend/src/browser.py | 6 ++- frontend/src/components/DeckyState.tsx | 8 +++ .../modals/PluginUninstallModal.tsx | 3 +- frontend/src/components/settings/index.tsx | 2 +- .../pages/plugin_list/PluginListLabel.tsx | 22 +++++++-- .../settings/pages/plugin_list/index.tsx | 30 ++++++++++-- frontend/src/frozen-plugins-service.tsx | 49 +++++++++++++++++++ frontend/src/plugin-loader.tsx | 7 ++- 9 files changed, 117 insertions(+), 12 deletions(-) create mode 100644 frontend/src/frozen-plugins-service.tsx diff --git a/backend/locales/en-US.json b/backend/locales/en-US.json index 7845ae4fe..eb229dfc2 100644 --- a/backend/locales/en-US.json +++ b/backend/locales/en-US.json @@ -99,12 +99,14 @@ } }, "PluginListIndex": { + "freeze": "Freeze updates", "hide": "Quick access: Hide", "no_plugin": "No plugins installed!", "plugin_actions": "Plugin Actions", "reinstall": "Reinstall", "reload": "Reload", "show": "Quick access: Show", + "unfreeze": "Allow updates", "uninstall": "Uninstall", "update_all_one": "Update 1 plugin", "update_all_other": "Update {{count}} plugins", diff --git a/backend/src/browser.py b/backend/src/browser.py index 966206671..6b88fc257 100644 --- a/backend/src/browser.py +++ b/backend/src/browser.py @@ -272,12 +272,16 @@ def cleanup_plugin_settings(self, name: str): Args: name (string): The name of the plugin """ + frozen_plugins = self.settings.getSetting("frozenPlugins", []) + if name in frozen_plugins: + frozen_plugins.remove(name) + self.settings.setSetting("frozenPlugins", frozen_plugins) + hidden_plugins = self.settings.getSetting("hiddenPlugins", []) if name in hidden_plugins: hidden_plugins.remove(name) self.settings.setSetting("hiddenPlugins", hidden_plugins) - plugin_order = self.settings.getSetting("pluginOrder", []) if name in plugin_order: diff --git a/frontend/src/components/DeckyState.tsx b/frontend/src/components/DeckyState.tsx index d20c8d86e..749e27ce0 100644 --- a/frontend/src/components/DeckyState.tsx +++ b/frontend/src/components/DeckyState.tsx @@ -8,6 +8,7 @@ import { VerInfo } from '../updater'; interface PublicDeckyState { plugins: Plugin[]; pluginOrder: string[]; + frozenPlugins: string[]; hiddenPlugins: string[]; activePlugin: Plugin | null; updates: PluginUpdateMapping | null; @@ -26,6 +27,7 @@ export interface UserInfo { export class DeckyState { private _plugins: Plugin[] = []; private _pluginOrder: string[] = []; + private _frozenPlugins: string[] = []; private _hiddenPlugins: string[] = []; private _activePlugin: Plugin | null = null; private _updates: PluginUpdateMapping | null = null; @@ -41,6 +43,7 @@ export class DeckyState { return { plugins: this._plugins, pluginOrder: this._pluginOrder, + frozenPlugins: this._frozenPlugins, hiddenPlugins: this._hiddenPlugins, activePlugin: this._activePlugin, updates: this._updates, @@ -67,6 +70,11 @@ export class DeckyState { this.notifyUpdate(); } + setFrozenPlugins(frozenPlugins: string[]) { + this._frozenPlugins = frozenPlugins; + this.notifyUpdate(); + } + setHiddenPlugins(hiddenPlugins: string[]) { this._hiddenPlugins = hiddenPlugins; this.notifyUpdate(); diff --git a/frontend/src/components/modals/PluginUninstallModal.tsx b/frontend/src/components/modals/PluginUninstallModal.tsx index e7ecbc993..5de0085ec 100644 --- a/frontend/src/components/modals/PluginUninstallModal.tsx +++ b/frontend/src/components/modals/PluginUninstallModal.tsx @@ -15,8 +15,9 @@ const PluginUninstallModal: FC = ({ name, title, butt closeModal={closeModal} onOK={async () => { await window.DeckyPluginLoader.callServerMethod('uninstall_plugin', { name }); - // uninstalling a plugin resets the hidden setting for it server-side + // uninstalling a plugin resets the frozen and 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 window.DeckyPluginLoader.frozenPluginsService.invalidate(); await window.DeckyPluginLoader.hiddenPluginsService.invalidate(); }} strTitle={title} diff --git a/frontend/src/components/settings/index.tsx b/frontend/src/components/settings/index.tsx index f3a764075..cf9def66b 100644 --- a/frontend/src/components/settings/index.tsx +++ b/frontend/src/components/settings/index.tsx @@ -24,7 +24,7 @@ export default function SettingsPage() { }, { title: t('SettingsIndex.plugins_title'), - content: , + content: , route: '/decky/settings/plugins', icon: , }, diff --git a/frontend/src/components/settings/pages/plugin_list/PluginListLabel.tsx b/frontend/src/components/settings/pages/plugin_list/PluginListLabel.tsx index a49f808f2..fec03e568 100644 --- a/frontend/src/components/settings/pages/plugin_list/PluginListLabel.tsx +++ b/frontend/src/components/settings/pages/plugin_list/PluginListLabel.tsx @@ -1,18 +1,34 @@ import { FC } from 'react'; import { useTranslation } from 'react-i18next'; -import { FaEyeSlash } from 'react-icons/fa'; +import { FaEyeSlash, FaLock } from 'react-icons/fa'; interface PluginListLabelProps { + frozen: boolean; hidden: boolean; name: string; version?: string; } -const PluginListLabel: FC = ({ name, hidden, version }) => { +const PluginListLabel: FC = ({ name, frozen, hidden, version }) => { const { t } = useTranslation(); return (
-
{version ? `${name} - ${version}` : name}
+
+ {name} + {version && ( + <> + {' - '} + + {frozen && ( + <> + {' '} + + )} + {version} + + + )} +
{hidden && (
}) { const { t } = useTranslation(); @@ -43,7 +52,7 @@ function PluginInteractables(props: { entry: ReorderableEntry } return null; } - const { name, update, version, onHide, onShow, hidden } = props.entry.data; + const { name, update, version, onHide, onShow, hidden, onFreeze, onUnfreeze, frozen, isDeveloper } = props.entry.data; const showCtxMenu = (e: MouseEvent | GamepadEvent) => { showContextMenu( @@ -84,6 +93,11 @@ function PluginInteractables(props: { entry: ReorderableEntry } ) : ( {t('PluginListIndex.hide')} )} + {frozen ? ( + {t('PluginListIndex.unfreeze')} + ) : ( + isDeveloper && {t('PluginListIndex.freeze')} + )} , e.currentTarget ?? window, ); @@ -138,8 +152,8 @@ type PluginData = { version?: string; }; -export default function PluginList() { - const { plugins, updates, pluginOrder, setPluginOrder, hiddenPlugins } = useDeckyState(); +export default function PluginList({ isDeveloper }: { isDeveloper: boolean }) { + const { plugins, updates, pluginOrder, setPluginOrder, frozenPlugins, hiddenPlugins } = useDeckyState(); const [_, setPluginOrderSetting] = useSetting( 'pluginOrder', plugins.map((plugin) => plugin.name), @@ -151,21 +165,27 @@ export default function PluginList() { }, []); const [pluginEntries, setPluginEntries] = useState[]>([]); + const frozenPluginsService = window.DeckyPluginLoader.frozenPluginsService; const hiddenPluginsService = window.DeckyPluginLoader.hiddenPluginsService; useEffect(() => { setPluginEntries( plugins.map(({ name, version }) => { + const frozen = frozenPlugins.includes(name); const hidden = hiddenPlugins.includes(name); return { - label: