Repository: ietf-tools/datatracker

Issue:
Sort rooms by size in the schedule editor
from @flynnliz:

The rooms don’t appear in order of size anymore. Early in the agenda making process it’s really important for the rooms to appear in ascending order of capacity so we can schedule sessions in the correctly sized rooms. It’s confusing that now the rooms appear out of order (currently they are, in order of room capacities: 100, 100, 150, 80, 80, 150, 250, 350).  Is there a way to make it so that the rooms always appear in the same relative order even if the columns are not unbroken?


Discussion:
This may be a trickier fix than it should be due to the way the editor grid is structured. The room sorting *does* take room size into account, but only after other factors. The relevant code is:
https://github.com/ietf-tools/datatracker/blob/5b6695a04c46e1756183272e8da4195f1ebea1a7/ietf/meeting/views.py#L661-L679
The critical step is the one right before `room.capacity` - if the rooms with identical timeslot structure are not grouped, the layout code will need substantial reworking.
If the sort is stable, what's the problem with moving the room size sort earlier?

The existing sorting ensures that rooms with the same set of timeslots will be neighbors in the list. Line 673 does this where it sorts the rooms by the list of timeslot times/durations. The significant thing about the sort key ordering is that any rooms equal on line 673 will also be equal on the higher priority sort keys. Moving room capacity earlier will split up rooms with identical timeslot sets.

The template renders headings and related HTML plumbing (swap timeslots buttons, etc) assuming that the rooms are grouped with neighbors having identical timeslot structure. It *might* work, resulting in a less compact page, but I haven't tried (and was worried when I wrote it, hence the comment). It's worth trying.

Resolving patch:
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -659,7 +659,9 @@ def prepare_timeslots_for_display(timeslots, rooms):
         sorted_rooms = sorted(
             rooms_with_timeslots,
             key=lambda room: (
-                # First, sort regular session rooms ahead of others - these will usually
+                # Sort higher capacity rooms first.
+                -room.capacity if room.capacity is not None else 1,  # sort rooms with capacity = None at end
+                # Sort regular session rooms ahead of others - these will usually
                 # have more timeslots than other room types.
                 0 if room_data[room.pk]['timeslot_count'] == max_timeslots else 1,
                 # Sort rooms with earlier timeslots ahead of later
@@ -669,8 +671,6 @@ def prepare_timeslots_for_display(timeslots, rooms):
                 # Sort by list of starting time and duration so that groups with identical
                 # timeslot structure will be neighbors. The grouping algorithm relies on this!
                 room_data[room.pk]['start_and_duration'],
-                # Within each group, sort higher capacity rooms first.
-                -room.capacity if room.capacity is not None else 1,  # sort rooms with capacity = None at end
                 # Finally, sort alphabetically by name
                 room.name
             )


Test patch:
diff --git a/ietf/meeting/tests_js.py b/ietf/meeting/tests_js.py
--- a/ietf/meeting/tests_js.py
+++ b/ietf/meeting/tests_js.py
@@ -134,7 +134,7 @@ def test_edit_meeting_schedule(self):
         self.assertEqual(session_info_container.find_element(By.CSS_SELECTOR, ".other-session .time").text, "not yet scheduled")
 
         # deselect
-        self.driver.find_element(By.CSS_SELECTOR, '.drop-target').click()
+        self.driver.find_element(By.CSS_SELECTOR, '.timeslot[data-type="regular"] .drop-target').click()
 
         self.assertEqual(session_info_container.find_elements(By.CSS_SELECTOR, ".title"), [])
         self.assertNotIn('other-session-selected', s2b_element.get_attribute('class'))
@@ -193,9 +193,9 @@ def test_edit_meeting_schedule(self):
 
         # violated due to constraints - both the timeslot and its timeslot label
         self.assertTrue(self.driver.find_elements(By.CSS_SELECTOR, '#timeslot{}.would-violate-hint'.format(slot1.pk)))
-        # Find the timeslot label for slot1 - it's the first timeslot in the first room group
+        # Find the timeslot label for slot1 - it's the first timeslot in the room group containing room 1
         slot1_roomgroup_elt = self.driver.find_element(By.CSS_SELECTOR,
-            '.day-flow .day:first-child .room-group:nth-child(2)'  # count from 2 - first-child is the day label
+            '.day-flow .day:first-child .room-group[data-rooms="1"]'
         )
         self.assertTrue(
             slot1_roomgroup_elt.find_elements(By.CSS_SELECTOR,