Skip to content

Commit b60939a

Browse files
committed
Change new meeting schedule editor to not layout the time slots on a
linear scale, instead lay them out horizontally per day in chronological order with a small amount of size hinting by interpolating the width depending on the duration of the timeslot/session. Solve the problem of labeling time slots that don't necessarily align by simply labeling each slot separately. Add scheduled time slot information to the session info in the bottom right corner. Add selector for hiding timeslots to make it possible to hide special morning sessions. Add requested duration to the sessions in the grid. Use a smaller font size for the grid and switch to a non-serif, more condensed font. Tweak the margins. The grid is now slightly smaller than the old editor. Fix a couple of bugs. - Legacy-Id: 18012
1 parent 8bd9e5d commit b60939a

5 files changed

Lines changed: 178 additions & 130 deletions

File tree

ietf/meeting/views.py

Lines changed: 23 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -508,20 +508,22 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
508508
assignments_by_session[a.session_id].append(a)
509509

510510
# Prepare timeslot layout, making a timeline per day scaled in
511-
# browser em units to ensure that everything lines up even if the
511+
# browser rem units to ensure that everything lines up even if the
512512
# timeslots are not the same in the different rooms
513513

514-
def timedelta_to_css_ems(timedelta):
515-
css_ems_per_hour = 5
516-
return timedelta.seconds / 60.0 / 60.0 * css_ems_per_hour
514+
min_duration = min(t.duration for t in timeslots_qs)
515+
max_duration = max(t.duration for t in timeslots_qs)
517516

518-
timeslots_by_day = defaultdict(list)
519-
for t in timeslots_qs:
520-
timeslots_by_day[t.time.date()].append(t)
517+
def timedelta_to_css_ems(timedelta):
518+
capped_min_d = max(min_duration, datetime.timedelta(minutes=30))
519+
capped_max_d = min(max_duration, datetime.timedelta(hours=4))
520+
capped_timedelta = min(max(capped_min_d, timedelta), capped_max_d)
521521

522-
day_min_max = []
523-
for day, timeslots in sorted(timeslots_by_day.items()):
524-
day_min_max.append((day, min(t.time for t in timeslots), max(t.end_time() for t in timeslots)))
522+
min_d_css_rems = 8
523+
max_d_css_rems = 10
524+
# interpolate
525+
scale = (capped_timedelta - capped_min_d) / (capped_max_d - capped_min_d) if capped_min_d != capped_max_d else 1
526+
return min_d_css_rems + (max_d_css_rems - min_d_css_rems) * scale
525527

526528
timeslots_by_room_and_day = defaultdict(list)
527529
room_has_timeslots = set()
@@ -530,58 +532,32 @@ def timedelta_to_css_ems(timedelta):
530532
timeslots_by_room_and_day[(t.location_id, t.time.date())].append(t)
531533

532534
days = []
533-
for day, day_min_time, day_max_time in day_min_max:
534-
day_labels = []
535-
day_width = timedelta_to_css_ems(day_max_time - day_min_time)
536-
537-
label_width = 4 # em
538-
539-
hourly_delta = 2
540-
541-
first_hour = int(math.ceil((day_min_time.hour + day_min_time.minute / 60.0) / hourly_delta) * hourly_delta)
542-
t = day_min_time.replace(hour=first_hour, minute=0, second=0, microsecond=0)
543-
544-
last_hour = int(math.floor((day_max_time.hour + day_max_time.minute / 60.0) / hourly_delta) * hourly_delta)
545-
end = day_max_time.replace(hour=last_hour, minute=0, second=0, microsecond=0)
546-
547-
while t <= end:
548-
left_offset = timedelta_to_css_ems(t - day_min_time)
549-
right_offset = day_width - left_offset
550-
if right_offset > label_width:
551-
# there's room for the label
552-
day_labels.append((t, 'left', left_offset))
553-
else:
554-
day_labels.append((t, 'right', right_offset))
555-
556-
t += datetime.timedelta(seconds=hourly_delta * 60 * 60)
557-
558-
if not day_labels:
559-
day_labels.append((day_min_time, 'left', 0))
560-
535+
for day in sorted(set(t.time.date() for t in timeslots_qs)):
561536
room_timeslots = []
562537
for r in rooms:
563538
if r.pk not in room_has_timeslots:
564539
continue
565540

566541
timeslots = []
567542
for t in timeslots_by_room_and_day.get((r.pk, day), []):
568-
timeslots.append({
569-
'timeslot': t,
570-
'offset': timedelta_to_css_ems(t.time - day_min_time),
571-
'width': timedelta_to_css_ems(t.end_time() - t.time),
572-
})
543+
t.layout_width = timedelta_to_css_ems(t.end_time() - t.time)
544+
timeslots.append(t)
573545

574546
room_timeslots.append((r, timeslots))
575547

576548
days.append({
577549
'day': day,
578-
'width': day_width,
579-
'time_labels': day_labels,
580550
'room_timeslots': room_timeslots,
581551
})
582552

583553
room_labels = [[r for r in rooms if r.pk in room_has_timeslots] for i in range(len(days))]
584554

555+
# possible timeslot start/ends
556+
timeslot_groups = defaultdict(set)
557+
for ts in timeslots_qs:
558+
ts.start_end_group = "ts-group-{}-{}".format(ts.time.strftime("%Y%m%d-%H%M"), int(ts.duration.total_seconds() / 60))
559+
timeslot_groups[ts.time.date()].add((ts.time, ts.end_time(), ts.start_end_group))
560+
585561
# prepare sessions
586562
for ts in timeslots_qs:
587563
ts.session_assignments = []
@@ -637,7 +613,7 @@ def cubehelix(i, total, hue=1.2, start_angle=0.5):
637613
elif s.name:
638614
s.scheduling_label = s.name
639615

640-
s.requested_duration_in_hours = s.requested_duration.seconds / 60.0 / 60.0
616+
s.requested_duration_in_hours = round(s.requested_duration.seconds / 60.0 / 60.0, 1)
641617

642618
session_layout_margin = 0.2
643619
s.layout_width = timedelta_to_css_ems(s.requested_duration) - 2 * session_layout_margin
@@ -688,6 +664,7 @@ def cubehelix(i, total, hue=1.2, start_angle=0.5):
688664
'js_data': json.dumps(js_data, indent=2),
689665
'days': days,
690666
'room_labels': room_labels,
667+
'timeslot_groups': sorted((d, list(sorted(t_groups))) for d, t_groups in timeslot_groups.items()),
691668
'unassigned_sessions': unassigned_sessions,
692669
'session_parents': session_parents,
693670
'hide_menu': True,

ietf/static/ietf/css/ietf.css

Lines changed: 59 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,81 +1022,66 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
10221022
}
10231023

10241024
.edit-meeting-schedule .edit-grid .day {
1025-
margin-right: 2.5em;
1025+
margin-left: 1em;
10261026
margin-bottom: 2em;
10271027
}
10281028

1029+
.edit-meeting-schedule .edit-grid .room-label-column .day {
1030+
margin-left: 0;
1031+
}
1032+
10291033
.edit-meeting-schedule .edit-grid .day-label {
10301034
height: 3em;
1031-
border-bottom: 2px solid transparent;
10321035
}
10331036

10341037
.edit-meeting-schedule .edit-grid .day-flow {
10351038
margin-left: 8em;
10361039
display: flex;
10371040
flex-wrap: wrap;
1038-
justify-content: space-between;
1039-
}
1040-
1041-
@media only screen and (max-width: 120em) {
1042-
/* if there's only room for two days, it looks a bit odd with space-between */
1043-
.edit-meeting-schedule .edit-grid .day-flow {
1044-
justify-content: flex-start;
1045-
}
1041+
justify-content: flex-start;
10461042
}
10471043

1048-
.edit-meeting-schedule .edit-grid .day-flow .day-label {
1049-
border-bottom: 2px solid #eee;
1044+
.edit-meeting-schedule .edit-grid .timeslots {
1045+
position: relative;
1046+
height: 4.5em;
1047+
padding-bottom: 0.15em;
10501048
}
10511049

1052-
.edit-meeting-schedule .edit-grid .timeline {
1050+
.edit-meeting-schedule .edit-grid .timeslot {
10531051
position: relative;
1054-
height: 1.6em;
1052+
display: inline-block;
1053+
background-color: #f4f4f4;
1054+
height: 100%;
1055+
overflow: hidden;
10551056
}
10561057

1057-
.edit-meeting-schedule .edit-grid .timeline > div {
1058+
.edit-meeting-schedule .edit-grid .timeslot .time-label {
1059+
display: flex;
10581060
position: absolute;
1061+
height: 100%;
1062+
width: 100%;
1063+
align-items: center;
1064+
justify-content: center;
1065+
color: #999;
10591066
}
10601067

1061-
.edit-meeting-schedule .edit-grid .timeline.timeslots {
1062-
height: 3.3em;
1063-
}
1064-
1065-
.edit-meeting-schedule .edit-grid .timeline .time-label {
1066-
font-size: smaller;
1067-
border-left: 2px solid #eee;
1068-
border-right: 2px solid #eee;
1069-
padding: 0 0.2em;
1070-
height: 1.3em;
1071-
}
1072-
1073-
.edit-meeting-schedule .edit-grid .timeline .time-label.text-left {
1074-
border-right: none;
1075-
}
1076-
1077-
.edit-meeting-schedule .edit-grid .timeline .time-label.text-right {
1078-
border-left: none;
1079-
}
1080-
1081-
.edit-meeting-schedule .timeslot {
1068+
.edit-meeting-schedule .edit-grid .timeslot .drop-target {
1069+
position: relative; /* this is merely to make sure we are positioned above the time labels */
10821070
display: flex;
10831071
flex-direction: row;
1084-
background-color: #eee;
10851072
height: 100%;
1086-
border-bottom: 0.15em solid #fff;
1087-
overflow: hidden;
10881073
}
10891074

1090-
.edit-meeting-schedule .timeslot.dropping {
1075+
.edit-meeting-schedule .edit-grid .timeslot.dropping {
10911076
background-color: #ccc;
10921077
transition: background-color 0.2s;
10931078
}
10941079

1095-
.edit-meeting-schedule .timeslot.overfull {
1080+
.edit-meeting-schedule .edit-grid .timeslot.overfull {
10961081
border-right: 2px dashed #fff; /* cut-off illusion */
10971082
}
10981083

1099-
.edit-meeting-schedule .timeslot.would-violate-hint {
1084+
.edit-meeting-schedule .edit-grid .timeslot.would-violate-hint {
11001085
background-color: #ffe0e0;
11011086
}
11021087

@@ -1111,7 +1096,6 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
11111096

11121097
.edit-meeting-schedule .formatted-constraints .encircled {
11131098
font-size: smaller;
1114-
cursor: help;
11151099
}
11161100

11171101
/* sessions */
@@ -1139,7 +1123,7 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
11391123
}
11401124

11411125
.edit-meeting-schedule .session.dragging {
1142-
opacity: 0.3;
1126+
opacity: 0.1;
11431127
transition: opacity 0.4s;
11441128
}
11451129

@@ -1148,6 +1132,11 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
11481132
margin-right: 0;
11491133
}
11501134

1135+
.edit-meeting-schedule .edit-grid, .edit-meeting-schedule .session {
1136+
font-family: arial, helvetica, sans-serif;
1137+
font-size: 11px;
1138+
}
1139+
11511140
.edit-meeting-schedule .session .session-label {
11521141
flex-grow: 1;
11531142
margin-left: 0.1em;
@@ -1208,6 +1197,7 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
12081197
left: 0;
12091198
width: 100%;
12101199
border-top: 0.2em solid #ccc;
1200+
margin-bottom: 2em;
12111201
background-color: #fff;
12121202
opacity: 0.95;
12131203
}
@@ -1217,21 +1207,24 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
12171207
}
12181208

12191209
.edit-meeting-schedule .unassigned-sessions {
1220-
display: flex;
1221-
flex-wrap: wrap;
1222-
align-items: flex-start;
12231210
margin-top: 0.5em;
12241211
min-height: 4em;
12251212
max-height: 13em;
12261213
overflow-y: auto;
1227-
background-color: #eee;
1214+
background-color: #f4f4f4;
12281215
}
12291216

12301217
.edit-meeting-schedule .unassigned-sessions.dropping {
12311218
background-color: #e5e5e5;
12321219
transition: background-color 0.2s;
12331220
}
12341221

1222+
.edit-meeting-schedule .unassigned-sessions .drop-target {
1223+
display: flex;
1224+
flex-wrap: wrap;
1225+
align-items: flex-start;
1226+
}
1227+
12351228
.edit-meeting-schedule .scheduling-panel .preferences {
12361229
margin: 0.5em 0;
12371230
}
@@ -1245,6 +1238,21 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
12451238
display: inline-block;
12461239
}
12471240

1241+
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body {
1242+
/*column-count: 3;*/
1243+
display: flex;
1244+
flex-flow: row wrap;
1245+
}
1246+
1247+
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body > * {
1248+
margin-right: 1.5em;
1249+
}
1250+
1251+
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body label {
1252+
display: block;
1253+
font-weight: normal;
1254+
}
1255+
12481256
.edit-meeting-schedule .session-parent-toggles {
12491257
margin-top: 1em;
12501258
}
@@ -1259,8 +1267,9 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
12591267

12601268
.edit-meeting-schedule .scheduling-panel .session-info-container {
12611269
padding-left: 0.5em;
1262-
flex: 0 0 20em;
1263-
max-height: 15em;
1270+
flex: 0 0 25em;
1271+
max-height: 25em;
1272+
font-size: 14px;
12641273
overflow-y: auto;
12651274
}
12661275

0 commit comments

Comments
 (0)