diff --git a/COLLECTION_REORDER_FIX.md b/COLLECTION_REORDER_FIX.md deleted file mode 100644 index 194f24e..0000000 --- a/COLLECTION_REORDER_FIX.md +++ /dev/null @@ -1,138 +0,0 @@ -# Collection Reordering Bug Fix - Implementation Plan - -## Problem Summary -Collection item reordering fails after content edits. Position updates work at API level but don't persist through the enhancement cycle, causing items to revert to original order after page refresh. - -## Root Cause Analysis -1. **Missing HTML Attributes**: `data-item-id` not injected during enhancement (around line 622 in `reconstructCollectionItems()`) -2. **API Design Flaw**: No bulk reorder endpoint, only individual item updates -3. **ID Generation Inconsistency**: Different patterns for initial items vs new items -4. **Attribute Naming Issues**: Collection containers incorrectly use `data-content-id`, content has special `collection-item-` prefixes -5. **Obsolete Attributes**: `data-content-type` no longer needed after HTML-only switch -6. **Dynamic vs Static**: Frontend dynamically injects IDs instead of getting them from enhanced HTML - -## Architecture Principles -- **Static Enhancement**: All IDs should be injected during enhancement, not dynamically by JavaScript -- **Unified ID Generation**: Same deterministic system for all entities (content, collections, items) -- **Clean Separation**: Collections manage structure, `.insertr` elements manage content -- **No Backwards Compatibility**: Clean slate approach, all test data can be cleared - -## Implementation Plan - -### Phase 1: Backend Enhancement Fixes - -#### File: `/home/fitz/insertr/internal/engine/engine.go` -- **Line 622**: Add `data-item-id` injection in `reconstructCollectionItems()` -- **Line 812**: Replace `initial-` ID pattern with unified generator -- **Line 734**: Replace timestamp-based ID pattern with unified generator -- **Line 107**: Change collection containers from `data-content-id` to `data-collection-id` - -#### File: `/home/fitz/insertr/internal/engine/injector.go` -- **Line 165**: Remove obsolete `data-content-type` attribute injection - -### Phase 2: Frontend API Updates - -#### File: `/home/fitz/insertr/lib/src/core/api-client.js` -- Add `reorderCollection()` method for bulk operations -- Remove `updateCollectionItemPosition()` method (individual updates) - -#### File: `/home/fitz/insertr/lib/src/ui/collection-manager.js` -- Remove dynamic ID injection logic (around line 286) -- Update attribute names from `data-collection-item-id` to `data-item-id` -- Replace individual position updates with bulk reorder calls - -### Phase 3: Backend API Enhancement - -#### File: `/home/fitz/insertr/internal/api/handlers.go` -- Add `ReorderCollection` handler for bulk position updates -- Endpoint: `PUT /api/sites/{siteId}/collections/{collectionId}/reorder` - -## Expected HTML Output Change - -### Before -```html -
-``` - -### After -```html ----``` - -## Implementation Steps - -### Day 1: Backend Enhancement -1. **Clear test data**: Clean database for fresh start -2. **Fix ID injection**: Add `data-item-id` attributes during enhancement -3. **Unify ID generation**: Replace inconsistent patterns with unified system -4. **Update attribute names**: Change `data-content-id` to `data-collection-id` for collections -5. **Remove obsolete attributes**: Clean up `data-content-type` - -### Day 2: Frontend Updates -1. **Remove dynamic injection**: Stop generating IDs in JavaScript -2. **Update attribute references**: Change to new naming convention -3. **Add bulk reorder API**: Implement `reorderCollection()` method -4. **Update collection manager**: Use bulk operations instead of individual updates - -### Day 3: Backend API -1. **Add bulk reorder endpoint**: Implement `ReorderCollection` handler -2. **Route configuration**: Add PUT endpoint for bulk reorder -3. **Database operations**: Efficient bulk position updates - -### Day 4: Testing & Validation -1. **Test enhancement cycle**: Verify positions persist after content edits -2. **Test reordering**: Ensure drag-and-drop works correctly -3. **Test page refresh**: Confirm order maintained after reload -4. **Cross-browser testing**: Verify compatibility - -## Current Status -- ✅ API endpoint accepts `site_id` as query parameter correctly -- ✅ Root cause analysis complete -- ✅ Implementation plan finalized -- ✅ **Phase 1 COMPLETE**: Backend enhancement injection implemented -- ✅ Unified ID generation across all entities (collections, items, content) -- ✅ Data attribute injection working (data-collection-id, data-item-id, data-content-id) -- ✅ Obsolete attributes removed (data-content-type) -- ✅ **Phase 2 COMPLETE**: Frontend API updates implemented -- ✅ Dynamic ID injection removed (except for new items from server) -- ✅ Attribute references updated to data-item-id -- ✅ Bulk reorderCollection() API method added -- ✅ Individual updateCollectionItemPosition() method removed -- ✅ Collection manager uses bulk reorder with optimistic UI -- ✅ **Phase 3 COMPLETE**: Backend bulk reorder endpoint implemented -- ✅ ReorderCollection handler added with transaction-based bulk updates -- ✅ PUT /api/collections/{id}/reorder route configured -- ✅ Updated sqlc queries to include last_edited_by in position updates -- ✅ Atomic transaction ensures consistency during bulk reorder operations - -## Test Environment -- Server: `just dev` (http://localhost:8080) -- Test site: `/sites/simple/` with testimonials collection -- Database: Shows position conflicts (multiple items at position 1) - -## Success Criteria ✅ -1. ✅ Collection items maintain order after content edits (Phase 1) -2. ✅ Drag-and-drop reordering works without page refresh (Phase 2+3) -3. ✅ Order persists through full enhancement cycles (Phase 1) -4. ✅ Clean HTML output with proper attributes (Phase 1) -5. ✅ No JavaScript errors in browser console (Phase 2) - -## 🎉 IMPLEMENTATION COMPLETE - -All three phases have been successfully implemented: - -**Phase 1**: ✅ Backend enhancement injection with unified ID generation -**Phase 2**: ✅ Frontend API updates with bulk operations and optimistic UI -**Phase 3**: ✅ Backend bulk reorder endpoint with atomic transactions - -Collection item reordering now works end-to-end with persistence through content edits! - -## Notes -- All test data can be cleared - no backwards compatibility needed -- Focus on clean implementation over migration -- HTML-first approach: all attributes come from server enhancement -- Performance: bulk operations instead of individual API calls \ No newline at end of file diff --git a/lib/package-lock.json b/lib/package-lock.json index f9cb9bc..4797486 100644 --- a/lib/package-lock.json +++ b/lib/package-lock.json @@ -311,6 +311,7 @@ "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, diff --git a/lib/src/core/editor.js b/lib/src/core/editor.js index c183e22..de5703c 100644 --- a/lib/src/core/editor.js +++ b/lib/src/core/editor.js @@ -79,7 +79,9 @@ export class InsertrEditor { initializeCollection(meta) { const collectionManager = new CollectionManager(meta, this.apiClient, this.auth); - collectionManager.initialize(); + if (collectionManager.collectionId) { + collectionManager.initialize(); + } } addClickHandler(element, meta) { diff --git a/lib/src/ui/collection-manager.js b/lib/src/ui/collection-manager.js index f842b30..adc25b2 100644 --- a/lib/src/ui/collection-manager.js +++ b/lib/src/ui/collection-manager.js @@ -18,9 +18,9 @@ export class CollectionManager { this.auth = auth; // Extract collection ID from container - this.collectionId = this.container.getAttribute('data-content-id'); + this.collectionId = this.container.getAttribute('data-collection-id'); if (!this.collectionId) { - console.error('❌ Collection container missing data-content-id attribute'); + console.error('❌ Collection container missing data-collection-id attribute'); return; } @@ -331,7 +331,7 @@ export class CollectionManager { * Add management controls to an item (remove, reorder) */ addItemControls(itemElement, index) { - if (this.itemControls.has(itemElement)) return; // Already has controls + if (!this.itemControls || this.itemControls.has(itemElement)) return; // Already has controls or not initialized const controls = document.createElement('div'); controls.className = 'insertr-item-controls';