diff --git a/docs/plugin-development.md b/docs/plugin-development.md index 96c44295a..992a6c3cc 100644 --- a/docs/plugin-development.md +++ b/docs/plugin-development.md @@ -1,17 +1,20 @@ -# WARNING WIP (HELP WANTED) - -These docs are a first draft and at many places plain wrong. I think the best way to figure out how to write a plugin is to check aut the example plugins: - -https://github.com/johannesjo/super-productivity/tree/master/packages/plugin-dev/ -https://github.com/johannesjo/super-productivity/tree/master/packages/plugin-dev/yesterday-tasks-plugin - -It is not super complicated, I think :) - ---- - # Super Productivity Plugin Development Guide -This guide covers everything you need to know about creating plugins for Super Productivity. +This is a comprehensive documentation of the Super Productivity Plugin System. This guide covers everything you need to know about creating plugins for Super Productivity. + +These docs might not always be perfectly up to date. You find the latest typescript interfaces here: +[types.ts](../packages/plugin-api/src/types.ts) + +Personally I think the best way to figure out how to write a plugin is to check out the example plugins: + +- [yesterday-tasks-plugin](../packages/plugin-dev/yesterday-tasks-plugin) +- [procrastination-buster](../packages/plugin-dev/procrastination-buster) +- [api-test-plugin](../packages/plugin-dev/api-test-plugin) + +If you want to build a sophisticated UI there is a boilerplate available for solidjs: +[boilerplate-solid-js](../packages/plugin-dev/boilerplate-solid-js) + +--- ## Table of Contents @@ -25,22 +28,17 @@ This guide covers everything you need to know about creating plugins for Super P ## Quick Start -### 1. Use the Plugin Boilerplate or copy example plugin - -https://github.com/johannesjo/super-productivity/tree/master/packages/plugin-dev/boilerplate-solid-js -https://github.com/johannesjo/super-productivity/tree/master/packages/plugin-dev/yesterday-tasks-plugin - -### 2. Basic Plugin Structure +### 1. Basic Plugin Structure ``` my-plugin/ ├── manifest.json # Plugin metadata (required) -├── plugin.js # Main plugin code (optional) -├── index.html # UI interface (optional) +├── plugin.js # Main plugin code that is launched when activated and when Super Productivity starts +├── index.html # UI interface (optional) => requires iFrame:true in manifest └── icon.svg # Plugin icon (optional) ``` -### 3. Minimal Example +### 2. Minimal Example **manifest.json:** @@ -51,7 +49,7 @@ my-plugin/ "version": "1.0.0", "description": "My first Super Productivity plugin", "manifestVersion": 1, - "minSupVersion": "8.0.0" + "minSupVersion": "14.0.0" } ``` @@ -85,21 +83,21 @@ The `manifest.json` file is required for all plugins and defines the plugin's me ### Manifest Fields -| Field | Type | Required | Description | -| ----------------- | -------- | -------- | ---------------------------------------------------------- | -| `id` | string | ✓ | Unique identifier for your plugin (use kebab-case) | -| `name` | string | ✓ | Display name shown to users | -| `version` | string | ✓ | Semantic version (e.g., "1.0.0") | -| `description` | string | ✓ | Brief description of what your plugin does | -| `manifestVersion` | number | ✓ | Currently must be `1` | -| `minSupVersion` | string | ✓ | Minimum Super Productivity version required | -| `author` | string | | Plugin author name | -| `homepage` | string | | Plugin website or repository URL | -| `icon` | string | | Path to icon file (SVG recommended) | -| `iFrame` | boolean | | Whether plugin uses iframe UI (default: false) | -| `sidePanel` | boolean | | Show plugin in side panel (default: false) | -| `permissions` | string[] | | The permissions the plugin needs (e.g., ["nodeExecution"]) | -| `hooks` | string[] | | App events to listen to | +| Field | Type | Required | Description | +| ----------------- | -------- | -------- | ------------------------------------------------------------------ | +| `id` | string | ✓ | Unique identifier for your plugin (use kebab-case) | +| `name` | string | ✓ | Display name shown to users | +| `version` | string | ✓ | Semantic version (e.g., "1.0.0") | +| `description` | string | ✓ | Brief description of what your plugin does | +| `manifestVersion` | number | ✓ | Currently must be `1` | +| `minSupVersion` | string | ✓ | Minimum Super Productivity version required | +| `author` | string | | Plugin author name | +| `homepage` | string | | Plugin website or repository URL | +| `icon` | string | | Path to icon file (SVG recommended) | +| `iFrame` | boolean | | Whether plugin uses iframe UI (default: false) | +| `sidePanel` | boolean | | Show plugin in side panel (default: false), requires `iFrame:true` | +| `permissions` | string[] | | The permissions the plugin needs (e.g., ["nodeExecution"]) | +| `hooks` | string[] | | App events to listen to | ### Complete Manifest Example @@ -110,7 +108,7 @@ The `manifest.json` file is required for all plugins and defines the plugin's me "version": "2.1.0", "description": "An advanced plugin with UI and hooks", "manifestVersion": 1, - "minSupVersion": "8.0.0", + "minSupVersion": "14.0.2", "author": "John Doe", "homepage": "https://github.com/johndoe/my-plugin", "icon": "icon.svg", @@ -129,7 +127,8 @@ Pure JavaScript plugins that run in a sandboxed environment with full API access **Use when:** -- You need to register UI components (buttons, menu items) +- For setup background stuff that is to be executed even when the plugin ui (iFrame) is not shown +- For registering and handling keyboard shortcuts - You want to listen to app hooks/events - You need programmatic interaction with tasks/projects @@ -159,7 +158,6 @@ Plugins that render custom UI in a sandboxed iframe. - You need custom UI/visualizations - You want to display charts, forms, or complex interfaces -- You prefer working with HTML/CSS **Important:** When using iframes, you must inline all CSS and JavaScript directly in the HTML file. External stylesheets and scripts are blocked for security reasons. @@ -244,39 +242,11 @@ Plugins that render custom UI in a sandboxed iframe. }); } }); - - // Error handling - window.addEventListener('error', (event) => { - console.error('Plugin error:', event.error); - }); ``` -### 3. Hybrid Plugins - -Combine both `plugin.js` and `index.html` for maximum flexibility. - -**plugin.js:** - -```javascript -// Register UI elements and hooks -PluginAPI.registerSidePanelButton({ - label: 'Open My Plugin', - icon: 'dashboard', - onClick: () => { - PluginAPI.showIndexHtmlAsView(); - }, -}); - -// Listen for events and update iframe -PluginAPI.registerHook(PluginAPI.Hooks.TASK_UPDATE, () => { - // Notify iframe about task update - // (iframe will receive this via PluginAPI events) -}); -``` - ## Available API Methods ### Data Operations @@ -416,6 +386,8 @@ PluginAPI.registerHook(PluginAPI.Hooks.ACTION, (action) => { ### Data Persistence +You can persist data that will also be synced vai the `persistDataSynced` and `loadSyncedData` APIs. For local storage I recommend using `localStorage`. + ```javascript // Save plugin data await PluginAPI.persistDataSynced('myKey', { count: 42 }); @@ -430,50 +402,25 @@ console.log(data); // { count: 42 } ### 1. Performance - **Lazy load resources**: Don't load everything on plugin initialization -- **Debounce expensive operations**: Use throttling for frequent events -- **Clean up resources**: Remove event listeners when appropriate +- **Be responsive with using resources**: Avoid heavy operations and don't save excessive amounts of data. +- **Keep it lightweight**: Super Productivity is not the only app on the users system and your plugin is not the only plugin. -### 2. Error Handling - -Always wrap async operations in try-catch blocks: - -```javascript -async function loadData() { - try { - const tasks = await PluginAPI.getTasks(); - // Process tasks - } catch (error) { - console.error('Failed to load tasks:', error); - PluginAPI.showSnack({ - msg: 'Error loading tasks', - type: 'ERROR', - }); - } -} -``` - -### 3. User Experience +### 2. User Experience - **Provide feedback**: Show loading states and confirmations - **Be non-intrusive**: Don't spam notifications -- **Follow the app's design**: Use Material icons and consistent styling -- **Respect user preferences**: Check dark mode, language settings +- **Follow the app's design**: Use the injected theme variables and try to keep styles minimal. +- **Respect user preferences**: Check dark mode, and language settings (if possible or stick to english if not) -### 4. Security +### 3. Security -- **Validate inputs**: Never trust user input -- **Avoid eval()**: Use safe JSON parsing instead -- **Sanitize HTML**: If displaying user content - **Request minimal permissions**: Only what you need -### 5. Iframe Development +### 4. Don't spam the logs -When developing iframe plugins: +`console.logs` should be kept to a minimum. 1. **Inline everything**: CSS and JavaScript must be in the HTML file -2. **Wait for API ready**: Listen for the `PluginApiReady` event -3. **Handle errors gracefully**: Iframes can fail to load -4. **Keep it lightweight**: Iframes add overhead ```html @@ -499,8 +446,7 @@ When developing iframe plugins: - JavaScript plugins run in isolated VM contexts - Iframe plugins run in sandboxed iframes with restricted permissions -- No access to Node.js APIs unless explicitly granted -- No access to file system or network unless through API +- No access to file system unless through API ### API Restrictions @@ -523,10 +469,9 @@ In iframe context, these methods are NOT available: ### 1. Local Development -1. Enable Developer Mode in Super Productivity settings -2. Use "Load Plugin from Folder" to test your plugin -3. Open DevTools (F12) to see console logs -4. Use the API Test Plugin as reference +1. Use "Load Plugin from Folder" to test your plugin +2. Open DevTools (F12 or Ctrl+Shift+i) to see console logs +3. Use the API Test Plugin as reference ### 2. Debugging Tips @@ -564,7 +509,6 @@ async function testAPI() { **API methods failing:** -- Ensure PluginAPI is ready before use - Check if method is available in current context - Verify permissions in manifest @@ -574,172 +518,18 @@ async function testAPI() { - Verify no external dependencies - Look for CSP violations in console -## Examples - -### Task Reporter Plugin - -```javascript -// plugin.js -let reportInterval; - -PluginAPI.registerHeaderButton({ - label: 'Start Report', - icon: 'assessment', - onClick: () => { - if (reportInterval) { - clearInterval(reportInterval); - reportInterval = null; - PluginAPI.showSnack({ msg: 'Reporting stopped', type: 'INFO' }); - } else { - reportInterval = setInterval(generateReport, 3600000); // Every hour - PluginAPI.showSnack({ msg: 'Reporting started', type: 'SUCCESS' }); - } - }, -}); - -async function generateReport() { - const tasks = await PluginAPI.getCurrentContextTasks(); - const completed = tasks.filter((t) => t.isDone).length; - const total = tasks.length; - - PluginAPI.notify({ - title: 'Hourly Report', - body: `Completed ${completed} of ${total} tasks`, - ico: 'pie_chart', - }); -} -``` - -### Custom Dashboard Plugin - -```html - - - - - - - -

Task Dashboard

-
-
-
- - -
-
Total Tasks
-
-
-
- - -
-
Completed
-
-
-
- - -
-
Projects
-
-
-
- - -
-
Tags
-
-
- - - - -``` - ## Resources - **Plugin API Types**: [@super-productivity/plugin-api](https://www.npmjs.com/package/@super-productivity/plugin-api) -- **Plugin Boilerplate**: [GitHub Repository](https://github.com/johannesjo/super-productivity-plugin-boilerplate) -- **Example Plugins**: Check the `src/app/features/plugin/plugins` directory -- **Community Plugins**: [Awesome Super Productivity](https://github.com/johannesjo/super-productivity#plugins) +- **Plugin Boilerplate**: [boilerplate-solid-js](../packages/plugin-dev/boilerplate-solid-js) +- **Example Plugins**: [plugin-dev](../packages/plugin-dev) +- **Community Plugins**: Coming Soon! ## Contributing If you create a useful plugin, consider: -1. Publishing it to npm -2. Submitting a PR to add it to the community plugins list -3. Sharing it in the Super Productivity discussions +1. Posting on reddit or GitHub discussions about it +2. Submitting a PR to add it to the community plugins list (coming soon) Happy plugin development! 🚀