Files
c-relay/docs/subscription_table_grouping_plan.md
2025-10-31 10:39:06 -04:00

5.4 KiB

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):

// 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 = `
        <td style="font-family: 'Courier New', monospace; font-size: 12px;">${wsiPointer}</td>
        <td style="font-family: 'Courier New', monospace; font-size: 12px;">${subscription.id || 'N/A'}</td>
        <!-- <td style="font-family: 'Courier New', monospace; font-size: 12px;">${clientIP}</td> -->
        <td>${durationStr}</td>
        <td>${filtersDisplay}</td>
    `;
    tableBody.appendChild(row);
});

Modified Code:

// 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 = `
        <td style="font-family: 'Courier New', monospace; font-size: 12px;">${wsiPointerDisplay}</td>
        <td style="font-family: 'Courier New', monospace; font-size: 12px;">${subscription.id || 'N/A'}</td>
        <!-- <td style="font-family: 'Courier New', monospace; font-size: 12px;">${clientIP}</td> -->
        <td>${durationStr}</td>
        <td>${filtersDisplay}</td>
    `;
    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