From 655d65ac8564a3538b8c53fcc478a6b1d87532ed Mon Sep 17 00:00:00 2001 From: Aleix Soler Date: Sat, 24 May 2025 21:37:06 +0200 Subject: [PATCH] feat: add command integration --- integrations/commands/command-integration.ts | 227 +++++++++++++++++++ main.ts | 53 ++--- 2 files changed, 240 insertions(+), 40 deletions(-) create mode 100644 integrations/commands/command-integration.ts diff --git a/integrations/commands/command-integration.ts b/integrations/commands/command-integration.ts new file mode 100644 index 0000000..def45b5 --- /dev/null +++ b/integrations/commands/command-integration.ts @@ -0,0 +1,227 @@ +// integrations/commands/command-integration.ts +import { App, Editor, MarkdownView, Notice, TFile } from 'obsidian'; +import { NoteStatusSettings } from '../../models/types'; +import { StatusService } from 'services/status-service'; +import { StatusDropdown } from 'components/status-dropdown'; +import { StatusPaneViewController } from 'views/status-pane-view'; +import NoteStatus from 'main'; + +export class CommandIntegration { + private app: App; + private plugin: NoteStatus; + private settings: NoteStatusSettings; + private statusService: StatusService; + private statusDropdown: StatusDropdown; + + constructor( + app: App, + plugin: NoteStatus, + settings: NoteStatusSettings, + statusService: StatusService, + statusDropdown: StatusDropdown + ) { + this.app = app; + this.plugin = plugin; + this.settings = settings; + this.statusService = statusService; + this.statusDropdown = statusDropdown; + } + + public updateSettings(settings: NoteStatusSettings): void { + this.settings = settings; + } + + public registerCommands(): void { + // Open status pane + this.plugin.addCommand({ + id: 'open-status-pane', + name: 'Open status pane', + callback: () => StatusPaneViewController.open(this.app) + }); + + // Change status of current note + this.plugin.addCommand({ + id: 'change-status', + name: 'Change status of current note', + checkCallback: (checking: boolean) => { + const file = this.app.workspace.getActiveFile(); + if (!file) return false; + + if (!checking) { + this.statusDropdown.openStatusDropdown({ files: [file] }); + } + return true; + } + }); + + // Insert status metadata + this.plugin.addCommand({ + id: 'insert-status-metadata', + name: 'Insert status metadata', + editorCheckCallback: (checking: boolean, editor: Editor, view: MarkdownView) => { + if (!view.file) return false; + + const statuses = this.statusService.getFileStatuses(view.file); + const hasNoStatus = statuses.length === 1 && statuses[0] === 'unknown'; + + if (!checking && hasNoStatus) { + this.statusService.insertStatusMetadataInEditor(editor); + new Notice('Status metadata inserted'); + } + return hasNoStatus; + } + }); + + // Cycle through statuses + this.plugin.addCommand({ + id: 'cycle-status', + name: 'Cycle to next status', + checkCallback: (checking: boolean) => { + const file = this.app.workspace.getActiveFile(); + if (!file) return false; + + if (!checking) { + this.cycleStatus(file); + } + return true; + } + }); + + // Quick status commands for common statuses + const quickStatuses = ['active', 'completed', 'onHold', 'dropped']; + quickStatuses.forEach(status => { + this.plugin.addCommand({ + id: `set-status-${status}`, + name: `Set status to ${status}`, + checkCallback: (checking: boolean) => { + const file = this.app.workspace.getActiveFile(); + if (!file) return false; + + if (!checking) { + this.statusService.handleStatusChange({ + files: file, + statuses: status, + operation: 'set' + }); + new Notice(`Status set to ${status}`); + } + return true; + } + }); + }); + + // Clear status + this.plugin.addCommand({ + id: 'clear-status', + name: 'Clear status (set to unknown)', + checkCallback: (checking: boolean) => { + const file = this.app.workspace.getActiveFile(); + if (!file) return false; + + if (!checking) { + this.statusService.handleStatusChange({ + files: file, + statuses: 'unknown', + operation: 'set' + }); + new Notice('Status cleared'); + } + return true; + } + }); + + // Copy status from current note + this.plugin.addCommand({ + id: 'copy-status', + name: 'Copy status from current note', + checkCallback: (checking: boolean) => { + const file = this.app.workspace.getActiveFile(); + if (!file) return false; + + if (!checking) { + const statuses = this.statusService.getFileStatuses(file); + (this.app as any).clipboard = statuses; + new Notice(`Copied status: ${statuses.join(', ')}`); + } + return true; + } + }); + + // Paste status to current note + this.plugin.addCommand({ + id: 'paste-status', + name: 'Paste status to current note', + checkCallback: (checking: boolean) => { + const file = this.app.workspace.getActiveFile(); + const clipboard = (this.app as any).clipboard; + if (!file || !clipboard || !Array.isArray(clipboard)) return false; + + if (!checking) { + this.statusService.handleStatusChange({ + files: file, + statuses: clipboard, + operation: 'set' + }); + new Notice(`Pasted status: ${clipboard.join(', ')}`); + } + return true; + } + }); + + // Toggle multiple statuses mode + this.plugin.addCommand({ + id: 'toggle-multiple-statuses', + name: 'Toggle multiple statuses mode', + callback: () => { + this.settings.useMultipleStatuses = !this.settings.useMultipleStatuses; + this.plugin.saveSettings(); + new Notice(`Multiple statuses mode ${this.settings.useMultipleStatuses ? 'enabled' : 'disabled'}`); + } + }); + + // Search notes by status + this.plugin.addCommand({ + id: 'search-by-status', + name: 'Search notes by current status', + checkCallback: (checking: boolean) => { + const file = this.app.workspace.getActiveFile(); + if (!file) return false; + + if (!checking) { + const statuses = this.statusService.getFileStatuses(file); + const query = `[${this.settings.tagPrefix}:"${statuses[0]}"]`; + (this.app as any).internalPlugins.getPluginById('global-search').instance.openGlobalSearch(query); + } + return true; + } + }); + } + + private cycleStatus(file: TFile): void { + const allStatuses = this.statusService.getAllStatuses() + .filter(s => s.name !== 'unknown') + .map(s => s.name); + + if (allStatuses.length === 0) { + new Notice('No statuses available'); + return; + } + + const currentStatuses = this.statusService.getFileStatuses(file); + const currentStatus = currentStatuses[0]; + + let nextIndex = 0; + if (currentStatus !== 'unknown') { + const currentIndex = allStatuses.indexOf(currentStatus); + nextIndex = (currentIndex + 1) % allStatuses.length; + } + + this.statusService.handleStatusChange({ + files: file, + statuses: allStatuses[nextIndex], + operation: 'set' + }); + + new Notice(`Status changed to ${allStatuses[nextIndex]}`); + } +} diff --git a/main.ts b/main.ts index 4522588..e380975 100644 --- a/main.ts +++ b/main.ts @@ -11,7 +11,8 @@ import { MetadataIntegration } from './integrations/metadata-cache'; import { WorkspaceIntegration } from './integrations/workspace'; import { FileContextMenuIntegration } from 'integrations/context-menu/file-context-menu-integration'; import { NoteStatusSettingTab } from 'integrations/settings/settings-tab'; -// +import { CommandIntegration } from 'integrations/commands/command-integration'; + // Importar vistas import { StatusPaneViewController } from './views/status-pane-view'; @@ -38,6 +39,7 @@ export default class NoteStatus extends Plugin { toolbarIntegration: ToolbarIntegration; metadataIntegration: MetadataIntegration; workspaceIntegration: WorkspaceIntegration; + commandIntegration: CommandIntegration; statusPane: StatusPaneViewController; @@ -98,7 +100,13 @@ export default class NoteStatus extends Plugin { this.fileContextMenuIntegration = new FileContextMenuIntegration(this.app, this.settings, this.statusService, this.explorerIntegration, statusContextMenu); this.editorIntegration = new EditorIntegration(this.app, this.settings, this.statusService, this.statusDropdown); - + this.commandIntegration = new CommandIntegration( + this.app, + this, + this.settings, + this.statusService, + this.statusDropdown + ); this.metadataIntegration = new MetadataIntegration( this.app, this.settings, @@ -116,47 +124,11 @@ export default class NoteStatus extends Plugin { // // 3. Registrar eventos en cada integración this.fileContextMenuIntegration.registerFileContextMenuEvents(); this.editorIntegration.registerEditorMenus(); - // this.metadataIntegration.registerMetadataEvents(); + this.commandIntegration.registerCommands(); this.metadataIntegration.registerMetadataEvents(); this.workspaceIntegration.registerWorkspaceEvents(); } - private registerCommands() { - // // Comando para actualizar estado - // this.addCommand({ - // id: 'refresh-status', - // name: 'Refresh status', - // callback: () => { - // this.refreshStatus(); - // new Notice('Note status refreshed!'); - // } - // }); - - // // Comando para forzar actualización de UI - // this.addCommand({ - // id: 'force-refresh-ui', - // name: 'Force refresh user interface', - // callback: () => this.forceRefreshUI() - // }); - - // // Comando para insertar metadatos de estado - // this.addCommand({ - // id: 'insert-status-metadata', - // name: 'Insert status metadata', - // editorCallback: (editor) => { - // this.editorIntegration.insertStatusMetadata(editor); - // new Notice('Status metadata inserted'); - // } - // }); - - // // Comando para abrir panel de estado - // this.addCommand({ - // id: 'open-status-pane', - // name: 'Open status pane', - // callback: () => this.openStatusPane() - // }); - } - private setupCustomEvents() { // Evento para cambios de estado @@ -237,7 +209,8 @@ this.metadataIntegration.registerMetadataEvents(); this.explorerIntegration.updateSettings(this.settings); this.fileContextMenuIntegration.updateSettings(this.settings); this.editorIntegration.updateSettings(this.settings); - //this.metadataIntegration.updateSettings(this.settings); + this.metadataIntegration?.updateSettings(this.settings); + this.commandIntegration?.updateSettings(this.settings); this.toolbarIntegration.updateSettings(this.settings); this.workspaceIntegration.updateSettings(this.settings); this.statusPane?.updateSettings(this.settings);