# Subscription Table WSI Pointer Grouping Implementation Plan ## Objective Modify the subscription details table to show the WSI Pointer value only once per group - on the first row of each WSI Pointer group, leaving it blank for subsequent rows with the same WSI Pointer. ## Current Behavior - All rows show the WSI Pointer value - Rows are sorted by WSI Pointer (grouping is working) - Visual grouping is not clear ## Desired Behavior - First row of each WSI Pointer group shows the full WSI Pointer value - Subsequent rows in the same group have an empty cell for WSI Pointer - This creates a clear visual grouping effect ## Implementation Details ### File to Modify `api/index.js` - Function `populateSubscriptionDetailsTable()` (lines 4277-4384) ### Code Changes Required #### Current Code (lines 4291-4383): ```javascript // Sort subscriptions by wsi_pointer to group them together subscriptionsData.sort((a, b) => { const wsiA = a.wsi_pointer || ''; const wsiB = b.wsi_pointer || ''; return wsiA.localeCompare(wsiB); }); subscriptionsData.forEach((subscription, index) => { const row = document.createElement('tr'); // Calculate duration const now = Math.floor(Date.now() / 1000); const duration = now - subscription.created_at; const durationStr = formatDuration(duration); // Format client IP (show full IP for admin view) const clientIP = subscription.client_ip || 'unknown'; // Format wsi_pointer (show full pointer) const wsiPointer = subscription.wsi_pointer || 'N/A'; // Format filters (show actual filter details) let filtersDisplay = 'None'; // ... filter formatting code ... row.innerHTML = ` ${wsiPointer} ${subscription.id || 'N/A'} ${durationStr} ${filtersDisplay} `; tableBody.appendChild(row); }); ``` #### Modified Code: ```javascript // Sort subscriptions by wsi_pointer to group them together subscriptionsData.sort((a, b) => { const wsiA = a.wsi_pointer || ''; const wsiB = b.wsi_pointer || ''; return wsiA.localeCompare(wsiB); }); // Track previous WSI Pointer to detect group changes let previousWsiPointer = null; subscriptionsData.forEach((subscription, index) => { const row = document.createElement('tr'); // Calculate duration const now = Math.floor(Date.now() / 1000); const duration = now - subscription.created_at; const durationStr = formatDuration(duration); // Format client IP (show full IP for admin view) const clientIP = subscription.client_ip || 'unknown'; // Format wsi_pointer - only show if it's different from previous row const currentWsiPointer = subscription.wsi_pointer || 'N/A'; let wsiPointerDisplay = ''; if (currentWsiPointer !== previousWsiPointer) { // This is the first row of a new group - show the WSI Pointer wsiPointerDisplay = currentWsiPointer; previousWsiPointer = currentWsiPointer; } else { // This is a continuation of the same group - leave blank wsiPointerDisplay = ''; } // Format filters (show actual filter details) let filtersDisplay = 'None'; // ... filter formatting code remains the same ... row.innerHTML = ` ${wsiPointerDisplay} ${subscription.id || 'N/A'} ${durationStr} ${filtersDisplay} `; tableBody.appendChild(row); }); ``` ### Key Changes Explained 1. **Add tracking variable**: `let previousWsiPointer = null;` before the forEach loop 2. **Store current WSI Pointer**: `const currentWsiPointer = subscription.wsi_pointer || 'N/A';` 3. **Compare with previous**: Check if `currentWsiPointer !== previousWsiPointer` 4. **Conditional display**: - If different: Show the WSI Pointer value and update `previousWsiPointer` - If same: Show empty string (blank cell) 5. **Use display variable**: Replace `${wsiPointer}` with `${wsiPointerDisplay}` in the row HTML ### Visual Result **Before:** ``` WSI Pointer | Subscription ID | Duration | Filters 0x12345678 | sub-001 | 5m 30s | kinds:[1] 0x12345678 | sub-002 | 3m 15s | kinds:[3] 0x87654321 | sub-003 | 1m 45s | kinds:[1,3] ``` **After:** ``` WSI Pointer | Subscription ID | Duration | Filters 0x12345678 | sub-001 | 5m 30s | kinds:[1] | sub-002 | 3m 15s | kinds:[3] 0x87654321 | sub-003 | 1m 45s | kinds:[1,3] ``` ## Testing Checklist 1. ✅ Verify first row of each group shows WSI Pointer 2. ✅ Verify subsequent rows in same group are blank 3. ✅ Verify grouping works with multiple subscriptions per WSI Pointer 4. ✅ Verify single subscription per WSI Pointer still shows the value 5. ✅ Verify empty/null WSI Pointers are handled correctly 6. ✅ Verify table still displays correctly when no subscriptions exist ## Next Steps 1. Review this plan 2. Switch to Code mode 3. Implement the changes in `api/index.js` 4. Test the implementation 5. Verify the visual grouping effect