{t('PluginListIndex.reinstall')}
@@ -130,7 +139,7 @@ type PluginData = {
};
export default function PluginList() {
- const { plugins, updates, pluginOrder, setPluginOrder } = useDeckyState();
+ const { plugins, updates, pluginOrder, setPluginOrder, hiddenPlugins } = useDeckyState();
const [_, setPluginOrderSetting] = useSetting
(
'pluginOrder',
plugins.map((plugin) => plugin.name),
@@ -141,22 +150,29 @@ export default function PluginList() {
window.DeckyPluginLoader.checkPluginUpdates();
}, []);
- const [pluginEntries, setPluginEntries] = useState[]>([]);
+ const [pluginEntries, setPluginEntries] = useState[]>([]);
+ const hiddenPluginsService = window.DeckyPluginLoader.hiddenPluginsService;
useEffect(() => {
setPluginEntries(
- plugins.map((plugin) => {
+ plugins.map(({ name, version }) => {
+ const hidden = hiddenPlugins.includes(name);
+
return {
- label: plugin.version ? `${plugin.name} - ${plugin.version}` : plugin.name,
+ label: ,
+ position: pluginOrder.indexOf(name),
data: {
- update: updates?.get(plugin.name),
- version: plugin.version,
+ name,
+ hidden,
+ version,
+ update: updates?.get(name),
+ onHide: () => hiddenPluginsService.update([...hiddenPlugins, name]),
+ onShow: () => hiddenPluginsService.update(hiddenPlugins.filter((pluginName) => name !== pluginName)),
},
- position: pluginOrder.indexOf(plugin.name),
};
}),
);
- }, [plugins, updates]);
+ }, [plugins, updates, hiddenPlugins]);
if (plugins.length === 0) {
return (
@@ -166,8 +182,8 @@ export default function PluginList() {
);
}
- function onSave(entries: ReorderableEntry[]) {
- const newOrder = entries.map((entry) => labelToName(entry.label, entry?.data?.version));
+ function onSave(entries: ReorderableEntry[]) {
+ const newOrder = entries.map((entry) => entry.data!.name);
console.log(newOrder);
setPluginOrder(newOrder);
setPluginOrderSetting(newOrder);
@@ -200,7 +216,7 @@ export default function PluginList() {
)}
- entries={pluginEntries} onSave={onSave} interactables={PluginInteractables} />
+ entries={pluginEntries} onSave={onSave} interactables={PluginInteractables} />
);
diff --git a/frontend/src/hidden-plugins-service.tsx b/frontend/src/hidden-plugins-service.tsx
new file mode 100644
index 00000000..0501c453
--- /dev/null
+++ b/frontend/src/hidden-plugins-service.tsx
@@ -0,0 +1,34 @@
+import { DeckyState } from './components/DeckyState';
+import { getSetting, setSetting } from './utils/settings';
+
+/**
+ * A Service class for managing the state and actions related to the hidden plugins feature
+ *
+ * It's mostly responsible for sending setting updates to the server and keeping the local state in sync.
+ */
+export class HiddenPluginsService {
+ constructor(private deckyState: DeckyState) {}
+
+ init() {
+ getSetting('hiddenPlugins', []).then((hiddenPlugins) => {
+ this.deckyState.setHiddenPlugins(hiddenPlugins);
+ });
+ }
+
+ /**
+ * Sends the new hidden plugins list to the server and persists it locally in the decky state
+ *
+ * @param hiddenPlugins The new list of hidden plugins
+ */
+ async update(hiddenPlugins: string[]) {
+ await setSetting('hiddenPlugins', hiddenPlugins);
+ this.deckyState.setHiddenPlugins(hiddenPlugins);
+ }
+
+ /**
+ * Refreshes the state of hidden plugins in the local state
+ */
+ async invalidate() {
+ this.deckyState.setHiddenPlugins(await getSetting('hiddenPlugins', []));
+ }
+}
diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx
index 57483293..6d20c2f0 100644
--- a/frontend/src/plugin-loader.tsx
+++ b/frontend/src/plugin-loader.tsx
@@ -1,5 +1,4 @@
import {
- ConfirmModal,
ModalRoot,
PanelSection,
PanelSectionRow,
@@ -18,9 +17,11 @@ import LegacyPlugin from './components/LegacyPlugin';
import { deinitFilepickerPatches, initFilepickerPatches } from './components/modals/filepicker/patches';
import MultiplePluginsInstallModal from './components/modals/MultiplePluginsInstallModal';
import PluginInstallModal from './components/modals/PluginInstallModal';
+import PluginUninstallModal from './components/modals/PluginUninstallModal';
import NotificationBadge from './components/NotificationBadge';
import PluginView from './components/PluginView';
import WithSuspense from './components/WithSuspense';
+import { HiddenPluginsService } from './hidden-plugins-service';
import Logger from './logger';
import { InstallType, Plugin } from './plugin';
import RouterHook from './router-hook';
@@ -45,6 +46,7 @@ class PluginLoader extends Logger {
private routerHook: RouterHook = new RouterHook();
public toaster: Toaster = new Toaster();
private deckyState: DeckyState = new DeckyState();
+ public hiddenPluginsService = new HiddenPluginsService(this.deckyState);
private reloadLock: boolean = false;
// stores a list of plugin names which requested to be reloaded
@@ -182,21 +184,8 @@ class PluginLoader extends Logger {
);
}
- public uninstallPlugin(name: string, title: string, button_text: string, description: string) {
- showModal(
- {
- await this.callServerMethod('uninstall_plugin', { name });
- }}
- onCancel={() => {
- // do nothing
- }}
- strTitle={title}
- strOKButtonText={button_text}
- >
- {description}
- ,
- );
+ public uninstallPlugin(name: string, title: string, buttonText: string, description: string) {
+ showModal();
}
public hasPlugin(name: string) {
@@ -220,6 +209,8 @@ class PluginLoader extends Logger {
console.log(pluginOrder);
this.deckyState.setPluginOrder(pluginOrder);
});
+
+ this.hiddenPluginsService.init();
}
public deinit() {