When splitting one operation into misc and tasks operations:
- Both operations now get unique ID suffixes (_misc and _tasks)
- Skip logic verifies both conditions before skipping:
1. tasks config has migrated field (isConfirmBeforeDelete)
2. misc config has NO migrated fields remaining
This prevents:
- Potential operation ID conflicts in the sync log
- Data loss in partial migration scenarios
Adds test cases for partial migration and correct skip scenarios.
Fixed i18n to fetch and use the current language when the plugin
initializes, instead of always defaulting to English. Now the plugin
will show the correct language immediately on first load, and also
update reactively when the language changes.
Changes:
- Added getCurrentLanguage() call in useTranslate initialization
- Changed onMount to createEffect for reactive language loading
- Updated both App.tsx and ProcrastinationInfo.tsx to use createEffect
- Applied fixes to both procrastination-buster and boilerplate
- Added debug logging to troubleshoot language change events
This fixes the issue where plugins always started in English regardless
of the user's selected language.
Fixed the message passing between plugin iframes and plugin.ts to use
the proper PLUGIN_MESSAGE/PLUGIN_MESSAGE_RESPONSE protocol instead of
custom messages. This ensures translations and other messages are
correctly routed through the plugin bridge.
Changes:
- Updated useTranslate to use PLUGIN_MESSAGE type
- Listen for PLUGIN_MESSAGE_RESPONSE instead of custom response
- Wrap message in { type, payload } structure
- Updated plugin.ts to read from message.payload
- Added debug logging for troubleshooting
- Applied fixes to both procrastination-buster and boilerplate
Changed message.data to message.payload in the onMessage handler
to match the structure sent by useTranslate hook. This fixes the
issue where translations were not loading in the UI.
Remove manual registerSidePanelButton() call since the side panel button
is already automatically registered via manifest.json with 'sidePanel: true'.
This fixes:
- Duplicate side panel button warning
- Plugin loading in both side panel and main view simultaneously
The manifest-based registration is sufficient and avoids duplication.
Add copyRecursive() helper function to handle both files and directories
when copying plugin builds to bundled-plugins. This ensures i18n folders
and other directories are properly copied.
Previously, only files were copied (checking isFile()), which caused i18n
folders to be skipped. Now all three plugin build commands (procrastination-
buster, sync-md, ai-productivity-prompts) properly copy directory trees.
Fixes: 404 errors for i18n/de.json and other directory contents
Replace PluginHooks.LANGUAGE_CHANGE enum reference with string literal
'languageChange' to fix runtime error. The type-only import of PluginHooks
was not available at runtime, causing "PluginHooks is not defined" error
when installing the plugin.
The hook registration now uses the string value directly:
- Before: plugin.registerHook(PluginHooks.LANGUAGE_CHANGE, ...)
- After: plugin.registerHook('languageChange', ...)
- Add comprehensive de.json with 80 German translation keys
- Update manifest.json to include German language support
- Translate all UI strings: home, navigation, strategies, info
- Translate all 8 procrastination types with emotions and strategies
- Translate educational content for understanding procrastination
All translation keys match between en.json and de.json for consistency.
- Add comprehensive English translations (en.json) for all UI strings
- Add useTranslate() hook for reactive translations
- Update manifest.json with i18n configuration
- Add i18n message handlers to plugin.ts
- Create getProcrastinationTypes() for dynamic translation loading
- Update App.tsx to use translations throughout
- Update ProcrastinationInfo.tsx with full translation support
- All 8 procrastination types, strategies, and info content now translatable
The plugin now supports internationalization with complete English translations
and can easily be extended to support additional languages.
- Add useTranslate() hook for reactive translations in SolidJS
- Include example translation files (en.json, de.json)
- Update Vite plugin to copy i18n folder during build
- Add i18n message handlers to plugin.ts
- Demonstrate i18n usage in App.tsx with ~10 translation keys
- Update documentation with comprehensive i18n guide
- Add i18n to features list in main plugin-dev README
The boilerplate now provides a complete working example of multi-language
plugin support, making it easy for developers to create internationalized
plugins.
Phase 7: Create documentation
- Create PLUGIN_I18N.md with complete i18n guide
- Quick start guide with file structure
- Manifest configuration details
- Translation file format and best practices
- Complete API documentation (translate, formatDate, getCurrentLanguage)
- Language change hook documentation
- Full list of supported languages (24 languages)
- Complete working example with multi-language support
- Best practices and troubleshooting sections
- Migration guide from hard-coded strings
- Testing and performance considerations
- Update README.md with i18n section
- Add i18n API methods to Plugin API section
- Add languageChange hook to hooks list
- Add i18n example to usage section
- Add i18n files to optional files list
- Add i18n best practice
- Link to comprehensive PLUGIN_I18N.md guide
Documentation provides complete guide for plugin developers to add
multi-language support to their plugins with working examples.
- Add i18n field to PluginManifest type in plugin-api package
- Create PluginI18nService for translation management
- Load translations from file paths or cached content
- Nested key lookup with dot notation (e.g., BUTTONS.SAVE)
- Smart fallback: current language → English → key
- Parameter interpolation with {{param}} syntax
- Language switching via signals
- Memory cleanup for unloaded plugins
- Add type validation for cached translation content
- Document language sync integration points
Part of plugin internationalization system implementation.
Tests will be added in Phase 8.
Replace inline `.toISOString().split('T')[0]` pattern with getDbDateStr()
utility across production code, tests, and plugin examples.
Changes:
- Production: 6 files (plugin-bridge, metrics, counters, task-repeat-cfg)
- Tests: 4 spec files (helper functions and direct uses)
- Plugin example: Added formatDateStr() helper matching main app pattern
This ensures consistent local timezone handling for all user-facing date
operations and provides a single source of truth for date string formatting.
Fixes#6021
When users manually added subtasks to markdown files that referenced
non-existent parent tasks, the plugin would crash due to unsafe null
assertions and missing validation. This made the plugin permanently
disabled and required creating a new markdown file to recover.
Changes:
- Added parent ID validation before creating operations
- Orphaned subtasks are now converted to root tasks with warnings
- Added comprehensive error handling with user notifications
- Plugin stays enabled even after sync errors
- Added 15 new tests (689 lines) for orphaned subtask scenarios
- Fixed all existing tests to support new error notifications
The fix implements defense-in-depth:
1. Validation layer: Check parent IDs exist before operations
2. Error handling: Catch and report errors without crashing
3. User feedback: Clear notifications about issues
4. Data preservation: No data loss, orphans become root tasks
- Remove placeholder address text from privacy policies (DE/EN)
- Expand HTML privacy policy with full GDPR disclosures:
- Legal bases (Art. 6), data subject rights (Art. 15-22)
- Supervisory authority, retention periods, DPA info
- Cookies/tracking and automated decision-making sections
- Align HTML terms with German ToS:
- Add proper termination notice periods (2 weeks/good cause)
- Add 6-week notice for ToS amendments
- Add consumer withdrawal rights (14 days)
- Add ODR platform link and jurisdiction info
The plugin was using a custom vite.config.ts that generated separate
JS/CSS files with broken relative paths. When loaded in a blob URL
iframe, these paths couldn't resolve.
- Switch to @super-productivity/vite-plugin which inlines assets
- Fix title from "Procrastination Buster" to "AI Productivity Prompts"
When uploading BACKUP_IMPORT via uploadSnapshot(), the client's op.id
was not sent to the server. The server would generate its own ID,
causing the client to not recognize the operation when downloaded later.
This led to data loss as the old backup state would be re-applied.
Changes:
- Add opId parameter to uploadSnapshot() interface
- Pass op.id from operation-log-upload.service.ts
- Send opId in SuperSync API request payload
- Server uses client's opId instead of generating new one
- Add E2E test to verify ID matching
The fix is backwards compatible - legacy clients without opId still work
as the server falls back to uuidv7() when opId is not provided.
Add explicit per-route rate limits to /verify-email and /magic-login
endpoints to address CodeQL security alerts. These endpoints previously
relied only on global rate limiting.
The shared-schema package was not being built before lint and test
steps in CI, causing "Cannot find module '@sp/shared-schema'" errors.
Changes:
- Add shared-schema:build script to package.json
- Update prepare script to build shared-schema first
- Add shared-schema to build-packages.js for completeness
The previous commit changed module resolution to bundler mode which
fixed Angular tests but broke Node.js ESM imports in super-sync-server.
Switch to tsup bundler that outputs both ESM (.mjs) and CJS (.js) formats,
with proper exports field to support both environments:
- CJS for super-sync-server (Node.js commonjs)
- ESM for Angular/webpack bundler imports