From bad92c6344cf1ddefce5030ca9f03cab2edcfb2e Mon Sep 17 00:00:00 2001 From: Aleix Soler Date: Fri, 21 Nov 2025 15:46:13 +0100 Subject: [PATCH] feat: gate dashboard and grouped status view behind experimental settings --- components/SettingsUI/UISettings.tsx | 37 ++++++++++ constants/defaultSettings.ts | 3 + core/commandsService.ts | 28 +++++--- integrations/commands/commandsIntegration.ts | 4 +- main.tsx | 76 ++++++++++++++++++-- types/pluginSettings.ts | 3 + 6 files changed, 134 insertions(+), 17 deletions(-) diff --git a/components/SettingsUI/UISettings.tsx b/components/SettingsUI/UISettings.tsx index 1a2ac0d..d39a76b 100644 --- a/components/SettingsUI/UISettings.tsx +++ b/components/SettingsUI/UISettings.tsx @@ -322,6 +322,43 @@ export const UISettings: React.FC = ({ settings, onChange }) => { /> +

Experimental features

+ + + + + + + + + + + + +

Behavior & Other

{ - await this.openStatusPane(); - }, - }); - this.registeredCommands.add("open-status-pane"); + // Open Status Pane command (experimental) + if (this.shouldEnableGroupedView()) { + this.plugin.addCommand({ + id: "open-status-pane", + name: "Open status pane", + callback: async () => { + await this.openStatusPane(); + }, + }); + this.registeredCommands.add("open-status-pane"); + } } private async openStatusPane(): Promise { @@ -356,6 +358,14 @@ export class CommandsService { this.registeredCommands.clear(); } + private shouldEnableGroupedView(): boolean { + const settings = settingsService.settings; + return ( + Boolean(settings.enableExperimentalFeatures) && + Boolean(settings.enableGroupedStatusView) + ); + } + public destroy(): void { // Remove all registered commands properly this.removeRegisteredCommands(); diff --git a/integrations/commands/commandsIntegration.ts b/integrations/commands/commandsIntegration.ts index 07d0f0e..2e28690 100644 --- a/integrations/commands/commandsIntegration.ts +++ b/integrations/commands/commandsIntegration.ts @@ -32,7 +32,9 @@ export class CommandsIntegration { if ( key === "quickStatusCommands" || key === "useMultipleStatuses" || - key === "templates" + key === "templates" || + key === "enableExperimentalFeatures" || + key === "enableGroupedStatusView" ) { this.commandsService.destroy(); /// BUG: if removed a command will persist because is not removed, you need the oldStates to send it to be disabled // const oldValue = this.settings[key]; // TODO: Send the old value diff --git a/main.tsx b/main.tsx index 81aa831..6cbbe06 100644 --- a/main.tsx +++ b/main.tsx @@ -27,6 +27,8 @@ export default class NoteStatusPlugin extends Plugin { private fileExplorerIntegration: FileExplorerIntegration; private commandsIntegration: CommandsIntegration; private editorToolbarIntegration: EditorToolbarIntegration; + private groupedViewRibbonEl: HTMLElement | null = null; + private dashboardRibbonEl: HTMLElement | null = null; async onload() { BaseNoteStatusService.initialize(this.app); @@ -53,13 +55,7 @@ export default class NoteStatusPlugin extends Plugin { (leaf) => new StatusDashboardView(leaf), ); - this.addRibbonIcon("list-tree", "Open grouped status view", () => { - this.activateView(); - }); - - this.addRibbonIcon("activity", "Open status dashboard", () => { - this.activateDashboard(); - }); + this.syncExperimentalFeatureShortcuts(); } async onunload() { @@ -70,6 +66,10 @@ export default class NoteStatusPlugin extends Plugin { this.commandsIntegration?.destroy(); this.editorToolbarIntegration?.destroy(); this.pluginSettingsIntegration?.destroy(); + this.groupedViewRibbonEl?.remove(); + this.groupedViewRibbonEl = null; + this.dashboardRibbonEl?.remove(); + this.dashboardRibbonEl = null; // Clean up event subscriptions eventBus.unsubscribe( @@ -148,6 +148,61 @@ export default class NoteStatusPlugin extends Plugin { } } + private canUseGroupedStatusView(): boolean { + const settings = settingsService.settings; + return ( + Boolean(settings.enableExperimentalFeatures) && + Boolean(settings.enableGroupedStatusView) + ); + } + + private canUseStatusDashboard(): boolean { + const settings = settingsService.settings; + return ( + Boolean(settings.enableExperimentalFeatures) && + Boolean(settings.enableStatusDashboard) + ); + } + + private syncExperimentalFeatureShortcuts(): void { + this.ensureGroupedViewRibbon(); + this.ensureDashboardRibbon(); + } + + private ensureGroupedViewRibbon(): void { + if (this.canUseGroupedStatusView()) { + if (!this.groupedViewRibbonEl) { + this.groupedViewRibbonEl = this.addRibbonIcon( + "list-tree", + "Open grouped status view", + () => { + this.activateView(); + }, + ); + } + } else if (this.groupedViewRibbonEl) { + this.groupedViewRibbonEl.remove(); + this.groupedViewRibbonEl = null; + } + } + + private ensureDashboardRibbon(): void { + if (this.canUseStatusDashboard()) { + if (!this.dashboardRibbonEl) { + this.dashboardRibbonEl = this.addRibbonIcon( + "activity", + "Open status dashboard", + () => { + this.activateDashboard(); + }, + ); + } + } else if (this.dashboardRibbonEl) { + this.dashboardRibbonEl.remove(); + this.dashboardRibbonEl = null; + } + } + private async loadEventBus() { // Propagate to custom event bus the new active file this.app.workspace.on( @@ -179,6 +234,13 @@ export default class NoteStatusPlugin extends Plugin { if (key === "enableStatusOverviewPopup" && value === false) { StatusesInfoPopup.close(); } + if ( + key === "enableExperimentalFeatures" || + key === "enableStatusDashboard" || + key === "enableGroupedStatusView" + ) { + this.syncExperimentalFeatureShortcuts(); + } }, "main-status-popup-setting-subscriptor", ); diff --git a/types/pluginSettings.ts b/types/pluginSettings.ts index c8e9a52..90af6f0 100644 --- a/types/pluginSettings.ts +++ b/types/pluginSettings.ts @@ -28,6 +28,9 @@ export type PluginSettings = { fileExplorerLeftBorder: boolean; // Whether to display a colored border on the explorer item fileExplorerStatusDot: boolean; // Whether to append a small colored dot next to the filename fileExplorerUnderlineFileName: boolean; // Whether to underline the filename using the status color + enableExperimentalFeatures: boolean; // Gate for experimental features + enableStatusDashboard: boolean; // Toggle for the status dashboard experiment + enableGroupedStatusView: boolean; // Toggle for the grouped status view experiment enabledTemplates: string[]; // IDs of enabled templates useCustomStatusesOnly: boolean; // Whether to use only custom statuses or include templates useMultipleStatuses: boolean; // Whether to allow multiple statuses per note