Fix collection manager JavaScript errors after attribute naming changes

- Update collection manager to use data-collection-id instead of data-content-id
- Add safety checks to prevent undefined Map access in addItemControls
- Add validation in editor to only initialize collections with valid collection IDs
- Resolves TypeError and missing attribute errors in frontend collection management
This commit is contained in:
2025-10-07 23:03:45 +02:00
parent 824719f07d
commit 2959ecedf9
4 changed files with 7 additions and 142 deletions

View File

@@ -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
<div class="testimonials insertr-add" data-content-id="index-testimonials-3ef43e">
<div class="testimonial-item"> <!-- Missing data-item-id -->
<blockquote class="insertr" data-content-id="collection-item-blockquote-756544" data-content-type="html">
```
### After
```html
<div class="testimonials insertr-add" data-collection-id="index-testimonials-3ef43e">
<div class="testimonial-item" data-item-id="index-testimonials-3ef43e-abc123">
<blockquote class="insertr" data-content-id="index-blockquote-def456">
```
## 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

1
lib/package-lock.json generated
View File

@@ -311,6 +311,7 @@
"integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"rollup": "dist/bin/rollup" "rollup": "dist/bin/rollup"
}, },

View File

@@ -79,7 +79,9 @@ export class InsertrEditor {
initializeCollection(meta) { initializeCollection(meta) {
const collectionManager = new CollectionManager(meta, this.apiClient, this.auth); const collectionManager = new CollectionManager(meta, this.apiClient, this.auth);
collectionManager.initialize(); if (collectionManager.collectionId) {
collectionManager.initialize();
}
} }
addClickHandler(element, meta) { addClickHandler(element, meta) {

View File

@@ -18,9 +18,9 @@ export class CollectionManager {
this.auth = auth; this.auth = auth;
// Extract collection ID from container // Extract collection ID from container
this.collectionId = this.container.getAttribute('data-content-id'); this.collectionId = this.container.getAttribute('data-collection-id');
if (!this.collectionId) { if (!this.collectionId) {
console.error('❌ Collection container missing data-content-id attribute'); console.error('❌ Collection container missing data-collection-id attribute');
return; return;
} }
@@ -331,7 +331,7 @@ export class CollectionManager {
* Add management controls to an item (remove, reorder) * Add management controls to an item (remove, reorder)
*/ */
addItemControls(itemElement, index) { 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'); const controls = document.createElement('div');
controls.className = 'insertr-item-controls'; controls.className = 'insertr-item-controls';