feat: gate dashboard and grouped status view behind experimental settings

This commit is contained in:
Aleix Soler 2025-11-21 15:46:13 +01:00
parent edacb2a9fa
commit bad92c6344
6 changed files with 134 additions and 17 deletions

View file

@ -322,6 +322,43 @@ export const UISettings: React.FC<Props> = ({ settings, onChange }) => {
/>
</SettingItem>
<h3>Experimental features</h3>
<SettingItem
name="Enable experimental features"
description="Unlock beta views that are still under development."
>
<input
type="checkbox"
checked={settings.enableExperimentalFeatures || false}
onChange={handleChange("enableExperimentalFeatures")}
/>
</SettingItem>
<SettingItem
name="Enable status dashboard"
description="Show the ribbon shortcut to open the status dashboard view."
>
<input
type="checkbox"
disabled={!settings.enableExperimentalFeatures}
checked={settings.enableStatusDashboard || false}
onChange={handleChange("enableStatusDashboard")}
/>
</SettingItem>
<SettingItem
name="Enable grouped status view"
description="Show the ribbon shortcut to open the grouped status view."
>
<input
type="checkbox"
disabled={!settings.enableExperimentalFeatures}
checked={settings.enableGroupedStatusView || false}
onChange={handleChange("enableGroupedStatusView")}
/>
</SettingItem>
<h3>Behavior & Other</h3>
<SettingItem

View file

@ -27,6 +27,9 @@ export const DEFAULT_PLUGIN_SETTINGS: PluginSettings = {
fileExplorerLeftBorder: false,
fileExplorerStatusDot: false,
fileExplorerUnderlineFileName: false,
enableExperimentalFeatures: true,
enableStatusDashboard: true,
enableGroupedStatusView: true,
enabledTemplates: DEFAULT_ENABLED_TEMPLATES,
useCustomStatusesOnly: false,
useMultipleStatuses: true,

View file

@ -229,15 +229,17 @@ export class CommandsService {
});
this.registeredCommands.add("search-by-status");
// Open Status Pane command
this.plugin.addCommand({
id: "open-status-pane",
name: "Open status pane",
callback: async () => {
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<void> {
@ -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();

View file

@ -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

View file

@ -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",
);

View file

@ -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