feat: add acronym text expansion#814
feat: add acronym text expansion#814marcpfuller wants to merge 9 commits intoGhostManager:masterfrom
Conversation
Implement Cmd+E/Ctrl+E shortcut to expand security acronyms inline. Ships with 50+ pre-loaded acronyms (XSS, CSRF, CIA, etc). Shows disambiguation modal for multi-match acronyms. Case-insensitive. - Add TipTap text expansion extension with keyboard shortcut - Add acronym disambiguation modal component - Add YAML acronym database (security/tech focused) - Add @rollup/plugin-yaml for build-time bundling - Update vite config to process YAML imports Signed-off-by: marc fuller <gogita99@gmail.com>
Signed-off-by: marc fuller <gogita99@gmail.com>
…ackage-lock.json Signed-off-by: marc fuller <gogita99@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a comprehensive acronym expansion system for the TipTap rich text editor with database-backed management, enabling users to automatically expand security and technology acronyms via Cmd/Ctrl+E. The system features a Django admin interface for CRUD operations, YAML bulk import capability, and a GraphQL API endpoint with JWT authentication.
Changes:
- Added database model, admin interface, and API endpoint for managing acronyms with filtering, priority-based ordering, and override capabilities
- Implemented TipTap extension with keyboard shortcut (Cmd/Ctrl+E) that auto-expands single-definition acronyms and highlights multi-definition acronyms for manual selection via modal
- Created migration to load 49 default security/technology acronyms from bundled YAML file on initial setup
Reviewed changes
Copilot reviewed 32 out of 34 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
javascript/vite.config.frontend.ts |
Added YAML plugin to support importing bundled acronym data |
javascript/vite.config.collab_server.ts |
Added YAML plugin for collab server build configuration |
javascript/src/tiptap_gw/text_expansion.ts |
Core TipTap extension implementing acronym detection, expansion logic, and ProseMirror decorations |
javascript/src/tiptap_gw/index.ts |
Registered TextExpansion extension with editor |
javascript/src/tiptap_gw/footnote.tsx |
Formatting updates (prettier/black) to existing footnote component |
javascript/src/tiptap_gw/acronym_api.ts |
API client for fetching acronyms from backend with fallback to bundled YAML |
javascript/src/frontend/collab_forms/rich_text_editor/text_expansion_modal.tsx |
React modal component for selecting from multiple acronym expansions |
javascript/src/frontend/collab_forms/rich_text_editor/text_expansion_button.tsx |
Toolbar button component for triggering acronym expansion |
javascript/src/frontend/collab_forms/rich_text_editor/index.tsx |
Integrated expansion modal and event handlers into editor |
javascript/src/frontend/collab_forms/editor.scss |
Styling for highlighted multi-definition acronyms |
javascript/src/data/acronyms.yml |
Default acronym definitions (49 security/technology terms) |
javascript/package.json |
Added @rollup/plugin-yaml dependency |
ghostwriter/reporting/views2/report.py |
Added AcronymYAMLUploadView for admin YAML import, formatting updates |
ghostwriter/reporting/utils.py |
YAML import logic with validation, override mode, and error handling |
ghostwriter/reporting/urls.py |
Added URL route for acronym YAML upload |
ghostwriter/reporting/tests/test_acronym_yaml.py |
Tests for YAML upload form, import functionality, and admin view |
ghostwriter/reporting/tests/test_acronym_model.py |
Tests for Acronym model CRUD operations, ordering, and filtering |
ghostwriter/reporting/tests/test_acronym_admin.py |
Tests for admin interface configuration and bulk actions |
ghostwriter/reporting/templates/reporting/acronym_yaml_upload.html |
User-facing YAML upload template |
ghostwriter/reporting/templates/admin/reporting/acronym_upload_yaml.html |
Admin YAML upload template |
ghostwriter/reporting/templates/admin/reporting/acronym_changelist.html |
Admin changelist template with upload button |
ghostwriter/reporting/models.py |
Added Acronym model with indexes for performance, formatting updates |
ghostwriter/reporting/migrations/0066_load_default_acronyms.py |
Data migration to load bundled acronyms on initial setup |
ghostwriter/reporting/migrations/0064_acronym_reporting_a_acronym_f840a2_idx_and_more.py |
Migration adding database indexes for acronym queries |
ghostwriter/reporting/migrations/0063_acronym.py |
Migration creating Acronym table |
ghostwriter/reporting/management/commands/check_acronyms.py |
Management command to display loaded acronyms |
ghostwriter/reporting/forms.py |
Added AcronymYAMLUploadForm with validation, formatting updates |
ghostwriter/reporting/admin.py |
Added AcronymAdmin with YAML upload, bulk actions, and fieldsets |
ghostwriter/factories.py |
Added AcronymFactory for testing, import ordering fix |
ghostwriter/api/views.py |
Added GraphqlGetAcronymsAction endpoint with filtering/pagination, formatting updates |
ghostwriter/api/urls.py |
Registered acronym API endpoint, import ordering updates |
ghostwriter/api/tests/test_acronym_api.py |
Tests for acronym API endpoint authentication, filtering, and responses |
Files not reviewed (1)
- javascript/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
ghostwriter/reporting/forms.py:1
- Using f-strings inside gettext translation calls (_()) prevents proper string extraction for internationalization. The variable parts should be passed as format arguments instead:
_('Acronym %s must have a list of expansions') % acronym
"""This contains all the forms used by the Reporting application."""
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #814 +/- ##
==========================================
- Coverage 91.37% 91.24% -0.14%
==========================================
Files 368 376 +8
Lines 20933 21565 +632
==========================================
+ Hits 19127 19676 +549
- Misses 1806 1889 +83 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Signed-off-by: marc fuller <gogita99@gmail.com>
4768e69 to
b779022
Compare
Signed-off-by: marc fuller <gogita99@gmail.com>

Issue
N/A
Description of the Change
This PR introduces a comprehensive acronym expansion system for the TipTap rich text editor with database-backed management. The feature enables users to automatically expand security and technology acronyms while writing reports.
Key Components:
Database Model & Admin Interface:
Acronymmodel with fields: acronym, expansion, priority, override_builtin, is_active, created_byYAML Bulk Import:
/admin/reporting/acronym/upload-yaml/GraphQL API Endpoint:
/api/getAcronymswith JWT authenticationFrontend Integration:
Data Migration:
Technical Implementation:
Alternate Designs
Considered Alternatives:
Static YAML only (no database): Rejected - inflexible for customer customization, requires rebuild for changes
REST ViewSet instead of Hasura action: Rejected - inconsistent with Ghostwriter's GraphQL-first architecture
Always show modal for all acronyms: Rejected - poor UX for common single-definition acronyms (API, XSS, etc.)
Client-scoped acronyms: Deferred - adds complexity, current global scope sufficient for v1
Possible Drawbacks
Network dependency: Editor requires API call to fetch custom acronyms on load (mitigated by bundled YAML fallback and caching in React state)
Migration overhead: New databases get 49 default acronyms loaded automatically (adds ~2-3 seconds to initial migration)
Admin-only upload: Only staff/superusers can bulk import acronyms (intentional security choice, but limits self-service for non-admin users)
Performance: Scanning entire document for acronyms on Cmd+E could be slow for very large documents (not observed in testing, but theoretical concern)
No collaborative filtering: All users see same acronym set - no per-user or per-project customization yet
Verification Process
Testing performed:
Backend Tests (58 tests, 0.584s):
Frontend Build:
Manual UI Testing:
Migration Testing:
docker compose -f local.yml run django python manage.py migrate docker compose -f local.yml run django python manage.py shell >>> from ghostwriter.reporting.models import Acronym >>> Acronym.objects.count() 49Verified 49 default acronyms loaded from bundled YAML
Regression Testing:
Release Notes
Added database-backed acronym expansion system with auto-expand on Cmd/Ctrl+E: single-definition acronyms expand immediately, multi-definition acronyms show click-to-select modal. Includes admin interface for CRUD operations, bulk YAML import, and 49 default security/technology acronyms. API endpoint enables dynamic loading with offline fallback.