manager: show date range in week view page title (#75010)
gitea/chrono/pipeline/head Build queued... Details

This commit is contained in:
Valentin Deniaud 2023-04-18 15:10:32 +02:00
parent 4ec41f3e09
commit 139f96672d
6 changed files with 127 additions and 44 deletions

View File

@ -1,5 +1,5 @@
{% extends "chrono/manager_agenda_date_view.html" %}
{% load i18n %}
{% load i18n chrono %}
{% block bodyargs %}class="weekview"{% endblock %}
@ -41,7 +41,7 @@
<a class="date-next pk-button" href="{{ view.get_next_week_url }}"><span class="sr-only">{% trans "Next week" %}</span></a>
</span>
<h2 class="date-nav">
<span class="date-title">{{ view.first_day|date:_("Y \w\e\e\k W") }}</span>
<span class="date-title">{{ view.first_day|human_date_range:view.last_day }}</span>
<button class="date-picker-opener"><span class="sr-only">{% trans "Pick a week" %}</span></button>
{% with selected_week=view.first_day|date:"W" selected_year=view.first_day|date:"Y" weeks=view.get_week_dates|get:view.first_day.year %}
<div class="date-picker" style="display: none">

View File

@ -1,5 +1,5 @@
{% extends "chrono/manager_resource_detail.html" %}
{% load i18n %}
{% load i18n chrono %}
{% block bodyargs %}class="weekview"{% endblock %}
@ -41,7 +41,7 @@
<a class="date-next pk-button" href="{{ view.get_next_week_url }}"><span class="sr-only">{% trans "Next week" %}</span></a>
</span>
<h2 class="date-nav">
<span class="date-title">{{ view.first_day|date:_("Y \w\e\e\k W") }}</span>
<span class="date-title">{{ view.first_day|human_date_range:view.last_day }}</span>
<button class="date-picker-opener"><span class="sr-only">{% trans "Pick a week" %}</span></button>
{% with selected_week=view.first_day|date:"W" selected_year=view.first_day|date:"Y" weeks=view.get_week_dates|get:view.first_day.year %}
<div class="date-picker" style="display: none">

View File

@ -0,0 +1,33 @@
# chrono - agendas system
# Copyright (C) 2023 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django import template
from django.utils.formats import date_format
register = template.Library()
@register.filter
def human_date_range(date_start, date_end):
date_end_format = 'd F Y'
if date_start.year != date_end.year:
date_start_format = date_end_format
elif date_start.month != date_end.month:
date_start_format = 'd F'
else:
date_start_format = 'd'
return '%s %s' % (date_format(date_start, date_start_format), date_format(date_end, date_end_format))

View File

@ -41,6 +41,7 @@ from django.utils import lorem_ipsum
from django.utils.dates import MONTHS
from django.utils.encoding import force_str
from django.utils.formats import date_format
from django.utils.functional import cached_property
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ngettext
@ -465,6 +466,32 @@ class ResourceWeekMonthMixin:
return context
@cached_property
def weekdays(self):
return TimePeriod.objects.filter(desk__agenda__resources=self.resource).values_list(
'weekday', flat=True
)
def get_active_events(self):
return [
x for x in self.object_list if any([y.cancellation_datetime is None for y in x.booking_set.all()])
]
@cached_property
def hide_sunday(self):
hide_sunday_timeperiod = 6 not in self.weekdays
hide_sunday_event = not any([x.start_datetime.weekday() == 6 for x in self.get_active_events()])
return hide_sunday_timeperiod and hide_sunday_event
@cached_property
def hide_weekend(self):
if not self.hide_sunday:
return False
hide_weekend_timeperiod = 5 not in self.weekdays
hide_weekend_event = not any([x.start_datetime.weekday() == 5 for x in self.get_active_events()])
return hide_weekend_timeperiod and hide_weekend_event
def get_timetable_infos(self):
interval = datetime.timedelta(minutes=60)
@ -474,29 +501,14 @@ class ResourceWeekMonthMixin:
)
min_timeperiod = timeperiods['start_time__min']
max_timeperiod = timeperiods['end_time__max']
hide_sunday_timeperiod = hide_weekend_timeperiod = hide_sunday_event = hide_weekend_event = True
weekdays = TimePeriod.objects.filter(desk__agenda__resources=self.resource).values_list(
'weekday', flat=True
)
if weekdays:
hide_sunday_timeperiod = 6 not in weekdays
hide_weekend_timeperiod = hide_sunday_timeperiod and 5 not in weekdays
active_events = [
x for x in self.object_list if any([y.cancellation_datetime is None for y in x.booking_set.all()])
]
active_events = self.get_active_events()
if active_events:
min_event = min(localtime(x.start_datetime).time() for x in active_events)
max_event = max(localtime(x.start_datetime + interval).time() for x in active_events)
hide_sunday_event = not any([x.start_datetime.weekday() == 6 for x in active_events])
hide_weekend_event = hide_sunday_event and not any(
[x.start_datetime.weekday() == 5 for x in active_events]
)
if min_timeperiod is None and min_event is None:
return
self.min_display = min(min_timeperiod or datetime.time(23), min_event or datetime.time(23))
self.max_display = max(max_timeperiod or datetime.time(0), max_event or datetime.time(0))
hide_sunday = hide_sunday_timeperiod and hide_sunday_event
hide_weekend = hide_weekend_timeperiod and hide_weekend_event
# avoid displaying empty first week
first_week_offset = 0
@ -504,8 +516,8 @@ class ResourceWeekMonthMixin:
last_week_number = first_week_number
if self.kind == 'month':
first_week_offset = int(
(hide_sunday and self.first_day.weekday() == 6)
or (hide_weekend and self.first_day.weekday() == 5)
(self.hide_sunday and self.first_day.weekday() == 6)
or (self.hide_weekend and self.first_day.weekday() == 5)
)
if first_week_number >= 52:
first_week_number = 0
@ -518,7 +530,7 @@ class ResourceWeekMonthMixin:
for week_number in range(first_week_number + first_week_offset, last_week_number + 1):
yield self.get_week_timetable_infos(
week_number - first_week_number,
week_end_offset=int(hide_sunday) + int(hide_weekend),
week_end_offset=int(self.hide_sunday) + int(self.hide_weekend),
)
def get_week_timetable_infos(self, week_index, week_end_offset=0):
@ -619,6 +631,10 @@ class ResourceWeekView(ResourceWeekMonthMixin, DateMixin, DayArchiveView, WeekMi
},
)
@property
def last_day(self):
return self.first_day + datetime.timedelta(days=6 - int(self.hide_sunday) - int(self.hide_weekend))
resource_weekly_view = ResourceWeekView.as_view()
@ -1521,38 +1537,53 @@ class AgendaWeekMonthMixin:
context['single_desk'] = bool(len(self.agenda.prefetched_desks) == 1)
return context
def get_timetable_infos(self):
timeperiods = list(itertools.chain(*(d.timeperiod_set.all() for d in self.agenda.prefetched_desks)))
def get_timeperiods(self):
return list(itertools.chain(*(d.timeperiod_set.all() for d in self.agenda.prefetched_desks)))
def get_active_events(self):
return [
x for x in self.object_list if any([y.cancellation_datetime is None for y in x.booking_set.all()])
]
@cached_property
def hide_sunday(self):
if self.agenda.kind == 'events':
return False
hide_sunday_timeperiod = not any(
[e.weekday == 6 or (e.date and e.date.weekday() == 6) for e in self.get_timeperiods()]
)
hide_sunday_event = not any([x.start_datetime.weekday() == 6 for x in self.get_active_events()])
return hide_sunday_timeperiod and hide_sunday_event
@cached_property
def hide_weekend(self):
if not self.hide_sunday:
return False
hide_weekend_timeperiod = not any(
[e.weekday == 5 or (e.date and e.date.weekday() == 5) for e in self.get_timeperiods()]
)
hide_weekend_event = not any([x.start_datetime.weekday() == 5 for x in self.get_active_events()])
return hide_weekend_timeperiod and hide_weekend_event
def get_timetable_infos(self):
timeperiods = self.get_timeperiods()
interval = datetime.timedelta(minutes=60)
min_timeperiod = max_timeperiod = min_event = max_event = None
hide_sunday_timeperiod = hide_weekend_timeperiod = hide_sunday_event = hide_weekend_event = True
if timeperiods:
min_timeperiod = min(x.start_time for x in timeperiods)
max_timeperiod = max(x.end_time for x in timeperiods)
hide_sunday_timeperiod = not any(
[e.weekday == 6 or (e.date and e.date.weekday() == 6) for e in timeperiods]
)
hide_weekend_timeperiod = hide_sunday_timeperiod and not any(
[e.weekday == 5 or (e.date and e.date.weekday() == 5) for e in timeperiods]
)
active_events = [
x for x in self.object_list if any([y.cancellation_datetime is None for y in x.booking_set.all()])
]
active_events = self.get_active_events()
if active_events:
min_event = min(localtime(x.start_datetime).time() for x in active_events)
max_event = max(localtime(x.start_datetime + interval).time() for x in active_events)
hide_sunday_event = not any([x.start_datetime.weekday() == 6 for x in active_events])
hide_weekend_event = hide_sunday_event and not any(
[x.start_datetime.weekday() == 5 for x in active_events]
)
if min_timeperiod is None and min_event is None:
return
self.min_display = min(min_timeperiod or datetime.time(23), min_event or datetime.time(23))
self.max_display = max(max_timeperiod or datetime.time(0), max_event or datetime.time(0))
hide_sunday = hide_sunday_timeperiod and hide_sunday_event
hide_weekend = hide_weekend_timeperiod and hide_weekend_event
# avoid displaying empty first week
first_week_offset = 0
@ -1560,8 +1591,8 @@ class AgendaWeekMonthMixin:
last_week_number = first_week_number
if self.kind == 'month':
first_week_offset = int(
(hide_sunday and self.first_day.weekday() == 6)
or (hide_weekend and self.first_day.weekday() == 5)
(self.hide_sunday and self.first_day.weekday() == 6)
or (self.hide_weekend and self.first_day.weekday() == 5)
)
first_week_number = self.first_day.isocalendar()[1]
if first_week_number >= 52:
@ -1575,7 +1606,7 @@ class AgendaWeekMonthMixin:
for week_number in range(first_week_number + first_week_offset, last_week_number + 1):
yield self.get_week_timetable_infos(
week_number - first_week_number,
week_end_offset=int(hide_sunday) + int(hide_weekend),
week_end_offset=int(self.hide_sunday) + int(self.hide_weekend),
)
def get_week_timetable_infos(self, week_index, week_end_offset=0):
@ -1720,6 +1751,10 @@ class AgendaWeekView(AgendaWeekMonthMixin, AgendaDateView, DayArchiveView, WeekM
def get_max_date(self):
return self.get_next_week(self.first_day.date())
@property
def last_day(self):
return self.first_day + datetime.timedelta(days=6 - int(self.hide_sunday) - int(self.hide_weekend))
agenda_weekly_view = AgendaWeekView.as_view()

View File

@ -1279,6 +1279,7 @@ def test_agenda_events_week_view(app, admin_user):
login(app)
resp = app.get('/manage/agendas/%s/week/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
assert '28 September 04 October 2020' in resp.text
assert '>Month<' in resp.text
assert '>Week<' in resp.text
assert '>Day<' in resp.text
@ -1310,6 +1311,7 @@ def test_agenda_events_week_view(app, admin_user):
assert len(resp.pyquery.find('.event-title')) == 2
assert resp.pyquery.find('.event-title')[0].text.strip() == 'abc'
assert resp.pyquery.find('.event-title')[1].text.strip() == 'xyz'
assert '09 15 November 2020' in resp.text
TimePeriodException.objects.create(
desk=agenda.desk_set.get(),
@ -2156,9 +2158,11 @@ def test_agenda_week_view_weekend(app, admin_user, kind):
assert 'Saturday' not in resp.text
# Month starts a Tuesday, but monday is displayed
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
assert '31 December 2018 04 January 2019' in resp.text
resp = app.get('/manage/agendas/%s/week/%s/%s/%s/' % (agenda.id, 2019, 6, 1)) # month starts a Saturday
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
assert '27 31 May 2019' in resp.text
saturday = 5
timeperiod_sat = TimePeriod.objects.create(
@ -2168,6 +2172,7 @@ def test_agenda_week_view_weekend(app, admin_user, kind):
assert 'Sunday' not in resp.text
assert 'Saturday' in resp.text
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
assert '27 May 01 June 2019' in resp.text
sunday = 6
TimePeriod.objects.create(
@ -2176,11 +2181,13 @@ def test_agenda_week_view_weekend(app, admin_user, kind):
resp = app.get('/manage/agendas/%s/week/%s/%s/%s/' % (agenda.id, 2019, 6, 1))
assert 'Sunday' in resp.text
assert 'Saturday' in resp.text
assert '27 May 02 June 2019' in resp.text
timeperiod_sat.delete()
resp = app.get('/manage/agendas/%s/week/%s/%s/%s/' % (agenda.id, 2019, 6, 1))
assert 'Sunday' in resp.text
assert 'Saturday' in resp.text
assert '27 May 02 June 2019' in resp.text
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
@ -3936,6 +3943,7 @@ def test_agenda_date_time_period_hide_weekend(app, admin_user, kind):
resp = app.get('/manage/agendas/%s/week/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
assert 'Sunday' not in resp.text
assert 'Saturday' not in resp.text
assert '14 18 November 2022' in resp.text
TimePeriod.objects.create(
desk=desk, date=today.replace(day=19), start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
@ -3950,6 +3958,7 @@ def test_agenda_date_time_period_hide_weekend(app, admin_user, kind):
resp = app.get('/manage/agendas/%s/week/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
assert 'Sunday' not in resp.text
assert 'Saturday' in resp.text
assert '14 19 November 2022' in resp.text
TimePeriod.objects.create(
desk=desk, date=today.replace(day=20), start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
@ -3964,6 +3973,7 @@ def test_agenda_date_time_period_hide_weekend(app, admin_user, kind):
resp = app.get('/manage/agendas/%s/week/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
assert 'Sunday' in resp.text
assert 'Saturday' in resp.text
assert '14 20 November 2022' in resp.text
@freezegun.freeze_time('2020-10-01')

View File

@ -315,11 +315,13 @@ def test_resource_week_view_weekend(app, admin_user):
assert 'Saturday' not in resp.text
# Month starts a Tuesday, but monday is displayed
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
assert '31 December 2018 04 January 2019' in resp.text
resp = app.get(
'/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, 2019, 6, 1)
) # month starts a Saturday
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
assert '27 31 May 2019' in resp.text
saturday = 5
timeperiod_sat = TimePeriod.objects.create(
@ -329,6 +331,7 @@ def test_resource_week_view_weekend(app, admin_user):
assert 'Sunday' not in resp.text
assert 'Saturday' in resp.text
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
assert '27 May 01 June 2019' in resp.text
sunday = 6
TimePeriod.objects.create(
@ -337,11 +340,13 @@ def test_resource_week_view_weekend(app, admin_user):
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, 2019, 6, 1))
assert 'Sunday' in resp.text
assert 'Saturday' in resp.text
assert '27 May 02 June 2019' in resp.text
timeperiod_sat.delete()
resp = app.get('/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, 2019, 6, 1))
assert 'Sunday' in resp.text
assert 'Saturday' in resp.text
assert '27 May 02 June 2019' in resp.text
def test_resource_week_view_opening_not_even_an_hour(app, admin_user):