* fix(plugin-bridge): enhance task update logic and validation for project movement
* fix(plugin-bridge): include changes in task update event payload
* feat(RuleEditor): add tests for rule editing functionality and enhance action handling
* test(RuleEditor): add comprehensive tests for rule editing and condition handling
* feat(RuleRegistry): enhance rule validation and add support for advanced conditions and actions
* feat(types): extend condition and action types for enhanced automation capabilities
* feat(conditions): add regex support for title conditions and enhance checks
* feat(actions): add ActionMoveToProject to move tasks between projects
* feat(ActionDialog, ActionInput): add support for moveToProject action and enhance input handling
* feat(ConditionDialog, ConditionInput): add support for titleStartsWith and weekdayIs conditions, enhance regex handling
* feat(styles): add new input-with-toggle and field-error styles for improved layout and error handling
* feat(automation): add titleStartsWith condition and enhance task event handling
* feat(automations): add delete task action
add a new `deleteTask` action to the automations plugin
- register the action in the automation runtime
- expose it in the rule editor UI
- restrict it to task-based triggers
- validate and persist rules using `deleteTask`
- add focused tests for runtime behavior, validation, persistence, and UI
* feat(automations): remove false trigger workaround
remove the temporary taskCreated fallback after confirming the
reported trigger bug was a mistaken assumption
* fix(automations): address PR review feedback
- Add regex pattern length cap (200 chars) to mitigate ReDoS risk
- Use project ID instead of title as option value to prevent duplicate name collisions
- Replace dynamic import('rxjs') with static import for firstValueFrom
- Replace any[] with proper types for projects/tags props
- Replace changes?: any with Record<string, unknown> in TaskEvent
- Use createMemo + <Show> for regexError to avoid double reactive computation
- Remove noisy/inconsistent debug logging from automation-manager
- Remove verbose intermediate log from moveToProject action
- Clean up mock: remove unused moveTaskToProject, restore PluginAPI type
- Prefer ID lookup over title in ActionMoveToProject
* fix(automations): harden regex, use IDs for conditions, add validation and tests
- Add dangerous-pattern heuristic to reject nested quantifiers (e.g. (a+)+$)
that cause catastrophic backtracking, supplementing the length cap
- Switch projectIs/hasTag condition dropdowns to store IDs instead of titles
to survive project/tag renames (with title fallback for backward compat)
- Disable ActionDialog Save button when value is empty (except deleteTask)
- Fix webhook test to actually validate payload sanitization
- Add test for HTML escaping in ActionDisplayDialog
- Add tests for regex length cap and dangerous-pattern rejection
- Add tests for ConditionWeekdayIs (7 test cases covering full names,
abbreviations, comma-separated lists, case insensitivity, edge cases)
* test(automations): build dangerous regex pattern dynamically to avoid CodeQL flag
The test intentionally uses a catastrophic-backtracking pattern to verify
our safety heuristic rejects it. Build it via string concatenation so
CodeQL's static analysis doesn't flag the test itself.
* fix(automations): addTag lookup by ID, widen ReDoS heuristic to catch {n,}
- ActionAddTag now looks up tags by ID first (with title fallback),
consistent with all other condition/action lookups
- Extend DANGEROUS_REGEX_PATTERN to also detect {n,} quantifiers
inside nested groups (e.g. (a{2,})+) which also cause backtracking
---------
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
|
||
|---|---|---|
| .. | ||
| scripts | ||
| src | ||
| .gitignore | ||
| .prettierrc | ||
| eslint.config.js | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
Solid.js Boilerplate Plugin for Super Productivity
A modern, TypeScript-based boilerplate for creating Super Productivity plugins using Solid.js.
Features
- 🚀 Solid.js - Fast, reactive UI framework
- 📘 TypeScript - Full type safety with Super Productivity Plugin API
- 🎨 Modern UI - Clean, responsive design with dark mode support
- 🔧 Vite - Lightning-fast development and build tooling
- 📦 Ready to Use - Complete setup with examples for all plugin features
Getting Started
Prerequisites
- Node.js 16+
- npm or yarn
- Super Productivity 8.0.0+
Installation
- Clone this boilerplate:
cd packages/plugin-dev
cp -r boilerplate-solid-js my-plugin
cd my-plugin
- Install dependencies:
npm install
- Update plugin metadata in
src/manifest.json:- Change
idto a unique identifier - Update
name,description, andauthor - Modify
permissionsandhooksas needed
- Change
Development
Run the development server:
npm run dev
This starts Vite in watch mode. Your plugin will rebuild automatically when you make changes.
Building
Build the plugin for production:
npm run build
This creates optimized files in the dist/ directory.
Packaging
Create a ZIP file for distribution:
npm run package
This will:
- Build the plugin
- Create a ZIP file containing all necessary files
- Place the ZIP in the root directory
Deployment (for Plugins with HTML UI)
If your plugin has an index.html file (for UI components, side panels, etc.), use the deploy command instead:
npm run deploy
This will:
- Build the plugin
- Inline all CSS and JavaScript assets into the HTML file
- Create a ZIP file for distribution
Note: The deploy command is necessary for any plugin with HTML UI because Super Productivity loads plugin HTML as data URLs, which cannot access external files. The inline-assets script ensures all assets are embedded directly in the HTML.
Project Structure
src/
├── assets/ # Static assets (icons, images)
│ └── icon.svg # Plugin icon
├── app/ # Solid.js application
│ ├── App.tsx # Main app component
│ └── App.css # App styles
├── index.html # Plugin UI entry point
├── index.ts # UI initialization
├── plugin.ts # Plugin logic and API integration
└── manifest.json # Plugin metadata
scripts/ # Build and utility scripts
└── build-plugin.js # Plugin packaging script
dist/ # Build output (gitignored)
├── assets/
├── index.html
├── index.js
├── plugin.js
└── manifest.json
Plugin API Usage
Basic Setup
The plugin API is exposed through the global plugin object in plugin.ts:
import { PluginInterface } from '@super-productivity/plugin-api';
declare const plugin: PluginInterface;
Common API Methods
UI Registration
// Register header button
plugin.registerHeaderButton({
icon: 'rocket',
tooltip: 'Open Plugin',
action: () => plugin.showIndexHtmlAsView(),
});
// Register menu entry
plugin.registerMenuEntry({
label: 'My Plugin',
icon: 'rocket',
action: () => plugin.showIndexHtmlAsView(),
});
// Register keyboard shortcut
plugin.registerShortcut({
keys: 'ctrl+shift+m',
label: 'Open My Plugin',
action: () => plugin.showIndexHtmlAsView(),
});
Data Operations
// Get tasks
const tasks = await plugin.getTasks();
const archivedTasks = await plugin.getArchivedTasks();
// Create task
const newTask = await plugin.addTask({
title: 'New Task',
projectId: 'project-id',
});
// Update task
await plugin.updateTask('task-id', {
title: 'Updated Title',
isDone: true,
});
// Get projects and tags
const projects = await plugin.getAllProjects();
const tags = await plugin.getAllTags();
Event Hooks
// Task completion
plugin.on('taskComplete', (task) => {
console.log('Task completed:', task.title);
});
// Task updates
plugin.on('taskUpdate', (task) => {
console.log('Task updated:', task);
});
// Context changes
plugin.on('contextChange', (context) => {
console.log('Context changed:', context);
});
Communication with UI
In plugin.ts:
plugin.onMessage('myCommand', async (data) => {
// Handle message from UI
return { result: 'success' };
});
In your Solid.js component:
const sendMessage = async (type: string, payload?: any) => {
return new Promise((resolve) => {
const messageId = Math.random().toString(36).substr(2, 9);
const handler = (event: MessageEvent) => {
if (event.data.messageId === messageId) {
window.removeEventListener('message', handler);
resolve(event.data.response);
}
};
window.addEventListener('message', handler);
window.parent.postMessage({ type, payload, messageId }, '*');
});
};
// Usage
const result = await sendMessage('myCommand', { foo: 'bar' });
Customization
Styling
The boilerplate includes:
- CSS custom properties for theming
- Dark mode support
- Responsive design
- Minimal, clean styling
Modify src/app/App.css to customize the appearance.
Adding Features
- New UI Components: Add them in
src/app/as.tsxfiles - New API Endpoints: Add handlers in
src/plugin.tsusingplugin.onMessage() - New Hooks: Register them in
manifest.jsonand handle inplugin.ts - Permissions: Add required permissions to
manifest.json
Best Practices
- Type Safety: Always use TypeScript types from
@super-productivity/plugin-api - Error Handling: Wrap async operations in try-catch blocks
- Performance: Use Solid.js signals and effects efficiently
- Security: Never expose sensitive data or operations
- User Experience: Provide loading states and error feedback
Deployment
- Build the plugin:
npm run build - Package it:
npm run package - Upload the ZIP file to Super Productivity:
- Open Super Productivity
- Go to Settings → Plugins
- Click "Upload Plugin"
- Select your ZIP file
Troubleshooting
Plugin not loading
- Check browser console for errors
- Verify
manifest.jsonis valid JSON - Ensure
minSupVersionmatches your Super Productivity version
API calls failing
- Check if you have required permissions in
manifest.json - Verify Super Productivity is running the correct version
- Look for error messages in the console
Build errors
- Run
npm run typecheckto check for TypeScript errors - Ensure all dependencies are installed
- Clear
node_modulesand reinstall if needed
Resources
License
This boilerplate is provided as-is for creating Super Productivity plugins. Feel free to modify and distribute your plugins as you see fit.