Skip to content

Commit 1d12391

Browse files
Indicate session and timeslot conflicts more prominently in schedule editor. Fixes ietf-tools#3221. Commit ready for merge.
- Legacy-Id: 19133
1 parent 197194a commit 1d12391

3 files changed

Lines changed: 102 additions & 16 deletions

File tree

ietf/meeting/tests_js.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,31 @@ def test_edit_meeting_schedule(self):
171171
s1_element = self.driver.find_element_by_css_selector('#session{}'.format(s1.pk))
172172
s1_element.click()
173173

174-
# violated due to constraints
174+
# violated due to constraints - both the timeslot and its timeslot label
175175
self.assertTrue(self.driver.find_elements_by_css_selector('#timeslot{}.would-violate-hint'.format(slot1.pk)))
176+
# Find the timeslot label for slot1 - it's the first timeslot in the first room group
177+
slot1_roomgroup_elt = self.driver.find_element_by_css_selector(
178+
'.day-flow .day:first-child .room-group:nth-child(2)' # count from 2 - first-child is the day label
179+
)
180+
self.assertTrue(
181+
slot1_roomgroup_elt.find_elements_by_css_selector(
182+
'.time-header > .time-label.would-violate-hint:first-child'
183+
),
184+
'Timeslot header label should show a would-violate hint for a constraint violation'
185+
)
186+
176187
# violated due to missing capacity
177188
self.assertTrue(self.driver.find_elements_by_css_selector('#timeslot{}.would-violate-hint'.format(slot3.pk)))
189+
# Find the timeslot label for slot3 - it's the second timeslot in the second room group
190+
slot3_roomgroup_elt = self.driver.find_element_by_css_selector(
191+
'.day-flow .day:first-child .room-group:nth-child(3)' # count from 2 - first-child is the day label
192+
)
193+
self.assertFalse(
194+
slot3_roomgroup_elt.find_elements_by_css_selector(
195+
'.time-header > .time-label.would-violate-hint:nth-child(2)'
196+
),
197+
'Timeslot header label should not show a would-violate hint for room capacity violation'
198+
)
178199

179200
# reschedule
180201
self.driver.execute_script("jQuery('#session{}').simulateDragDrop({{dropTarget: '#timeslot{} .drop-target'}});".format(s2.pk, slot2.pk))
@@ -192,6 +213,7 @@ def test_edit_meeting_schedule(self):
192213

193214
# constraint hints
194215
s1_element.click()
216+
self.assertIn('would-violate-hint', s2_element.get_attribute('class'))
195217
constraint_element = s2_element.find_element_by_css_selector(".constraints span[data-sessions=\"{}\"].would-violate-hint".format(s1.pk))
196218
self.assertTrue(constraint_element.is_displayed())
197219

ietf/static/ietf/css/ietf.css

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,11 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
10801080
align-items: center;
10811081
}
10821082

1083+
.edit-meeting-schedule .edit-grid .time-header .time-label.would-violate-hint {
1084+
background-color: #ffe0e0;
1085+
outline: #ffe0e0 solid 0.4em;
1086+
}
1087+
10831088
.edit-meeting-schedule .edit-grid .time-header .time-label span {
10841089
display: inline-block;
10851090
width: 100%;
@@ -1124,11 +1129,12 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
11241129
}
11251130

11261131
.edit-meeting-schedule .edit-grid .timeslot.overfull {
1127-
border-right: 2px dashed #fff; /* cut-off illusion */
1132+
border-right: 0.3em dashed #f55000; /* cut-off illusion */
11281133
}
11291134

11301135
.edit-meeting-schedule .edit-grid .timeslot.would-violate-hint {
11311136
background-color: #ffe0e0;
1137+
outline: #ffe0e0 solid 0.4em;
11321138
}
11331139

11341140
.edit-meeting-schedule .constraints .encircled,
@@ -1177,6 +1183,11 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
11771183
background-color: #f3f3f3;
11781184
}
11791185

1186+
.edit-meeting-schedule .session.would-violate-hint {
1187+
outline: 0.3em solid #F55000;
1188+
z-index: 1; /* raise up so the outline is not overdrawn */
1189+
}
1190+
11801191
.edit-meeting-schedule .session.highlight .session-label {
11811192
font-weight: bold;
11821193
}
@@ -1259,6 +1270,7 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
12591270
margin-bottom: 2em;
12601271
background-color: #fff;
12611272
opacity: 0.95;
1273+
z-index: 5; /* raise above edit-grid items */
12621274
}
12631275

12641276
.edit-meeting-schedule .scheduling-panel .unassigned-container {

ietf/static/ietf/js/edit-meeting-schedule.js

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jQuery(document).ready(function () {
1010

1111
let sessions = content.find(".session").not(".readonly");
1212
let timeslots = content.find(".timeslot");
13+
let timeslotLabels = content.find(".time-label");
1314
let days = content.find(".day-flow .day");
1415

1516
// hack to work around lack of position sticky support in old browsers, see https://caniuse.com/#feat=css-sticky
@@ -68,41 +69,92 @@ jQuery(document).ready(function () {
6869
}
6970
}
7071

72+
/**
73+
* Mark or unmark a session that conflicts with the selected session
74+
*
75+
* @param constraintElt The element corresponding to the specific constraint
76+
* @param wouldViolate True to mark or false to unmark
77+
*/
78+
function setSessionWouldViolate(constraintElt, wouldViolate) {
79+
constraintElt = jQuery(constraintElt);
80+
let constraintDiv = constraintElt.closest('div.session'); // find enclosing session div
81+
constraintDiv.toggleClass('would-violate-hint', wouldViolate); // mark the session container
82+
constraintElt.toggleClass('would-violate-hint', wouldViolate); // and the specific constraint
83+
}
84+
85+
/**
86+
* Mark or unmark a timeslot that conflicts with the selected session
87+
*
88+
* If wholeInterval is true, marks the entire column in addition to the timeslot.
89+
* This currently works by setting the class for the timeslot and the time-label
90+
* in its column. Because this is called for every timeslot in the interval, the
91+
* overall effect is to highlight the entire column.
92+
*
93+
* @param timeslotElt Timeslot element to be marked/unmarked
94+
* @param wouldViolate True to mark or false to unmark
95+
* @param wholeInterval Should the entire time interval be flagged or just the timeslot?
96+
*/
97+
function setTimeslotWouldViolate(timeslotElt, wouldViolate, wholeInterval) {
98+
timeslotElt = jQuery(timeslotElt);
99+
timeslotElt.toggleClass('would-violate-hint', wouldViolate);
100+
if (wholeInterval) {
101+
let index = timeslotElt.index(); // position of this timeslot relative to its container
102+
let label = timeslotElt
103+
.closest('div.room-group')
104+
.find('div.time-header .time-label')
105+
.get(index); // get time-label corresponding to this timeslot
106+
jQuery(label).toggleClass('would-violate-hint', wouldViolate);
107+
}
108+
}
109+
110+
/**
111+
* Remove all would-violate-hint classes on timeslots
112+
*/
113+
function resetTimeslotsWouldViolate() {
114+
timeslots.removeClass("would-violate-hint");
115+
timeslotLabels.removeClass("would-violate-hint");
116+
}
117+
71118
function showConstraintHints(selectedSession) {
72119
let sessionId = selectedSession ? selectedSession.id.slice("session".length) : null;
73120
// hints on the sessions
74121
sessions.find(".constraints > span").each(function () {
75-
if (!sessionId) {
76-
jQuery(this).removeClass("would-violate-hint");
77-
return;
122+
let wouldViolate = false;
123+
let applyChange = true;
124+
if (sessionId) {
125+
let sessionIds = this.dataset.sessions;
126+
if (!sessionIds) {
127+
applyChange = False;
128+
} else {
129+
wouldViolate = sessionIds.split(",").indexOf(sessionId) !== -1;
130+
}
78131
}
79132

80-
let sessionIds = this.dataset.sessions;
81-
if (!sessionIds)
82-
return;
83-
84-
let wouldViolate = sessionIds.split(",").indexOf(sessionId) != -1;
85-
jQuery(this).toggleClass("would-violate-hint", wouldViolate);
133+
if (applyChange) {
134+
setSessionWouldViolate(this, wouldViolate);
135+
}
86136
});
87137

88138
// hints on timeslots
89-
timeslots.removeClass("would-violate-hint");
139+
resetTimeslotsWouldViolate();
90140
if (selectedSession) {
91141
let intervals = [];
92142
timeslots.filter(":has(.session .constraints > span.would-violate-hint)").each(function () {
93143
intervals.push([this.dataset.start, this.dataset.end]);
94144
});
95145

96146
let overlappingTimeslots = findTimeslotsOverlapping(intervals);
97-
for (let i = 0; i < overlappingTimeslots.length; ++i)
98-
overlappingTimeslots[i].addClass("would-violate-hint");
147+
for (let i = 0; i < overlappingTimeslots.length; ++i) {
148+
setTimeslotWouldViolate(overlappingTimeslots[i], true, true);
149+
}
99150

100151
// check room sizes
101152
let attendees = +selectedSession.dataset.attendees;
102153
if (attendees) {
103154
timeslots.not(".would-violate-hint").each(function () {
104-
if (attendees > +jQuery(this).closest(".timeslots").data("roomcapacity"))
105-
jQuery(this).addClass("would-violate-hint");
155+
if (attendees > +jQuery(this).closest(".timeslots").data("roomcapacity")) {
156+
setTimeslotWouldViolate(this, true, false);
157+
}
106158
});
107159
}
108160
}

0 commit comments

Comments
 (0)