diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue index 3a07a036f050218119366825a9de30527709eec4..650e1aeb90810a9fa5f3366e5e9db59a00daca58 100644 --- a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue +++ b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue @@ -12,32 +12,48 @@ hide-default-footer > <template #additionalActions="{ attrs, on }"> - <v-autocomplete - :items="selectable" - item-text="name" - clearable - return-object - filled - dense - hide-details - :placeholder="$t('alsijil.coursebook.filter.filter_for_obj')" - :loading="selectLoading" - :value="currentObj" - @input="changeSelection" - @click:clear="changeSelection" - /> - <v-switch - :loading="selectLoading" - :label="$t('alsijil.coursebook.filter.own')" - :input-value="filterType === 'my'" - @change=" - changeSelection({ - filterType: $event ? 'my' : 'all', - type: objType, - id: objId, - }) - " - /> + <div class="d-flex flex-grow-1 justify-end"> + <v-autocomplete + :items="selectable" + item-text="name" + clearable + return-object + filled + dense + hide-details + :placeholder="$t('alsijil.coursebook.filter.filter_for_obj')" + :loading="selectLoading" + :value="currentObj" + @input="changeSelection" + @click:clear="changeSelection" + class="max-width" + /> + <div class="ml-6"> + <v-switch + :loading="selectLoading" + :label="$t('alsijil.coursebook.filter.own')" + :input-value="filterType === 'my'" + @change=" + changeSelection({ + filterType: $event ? 'my' : 'all', + type: objType, + id: objId, + }) + " + dense + inset + hide-details + /> + <v-switch + :loading="selectLoading" + :label="$t('alsijil.coursebook.filter.missing')" + v-model="incomplete" + dense + inset + hide-details + /> + </div> + </div> </template> <template #default="{ items }"> <v-list-item @@ -140,6 +156,7 @@ export default { courses: [], dateStart: null, dateEnd: null, + incomplete: false, }; }, apollo: { @@ -161,6 +178,7 @@ export default { dateEnd: this.dateEnd ?? DateTime.fromISO(this.date).plus({ weeks: 1 }).toISODate(), + incomplete: !!this.incomplete, }; }, selectable() { @@ -282,3 +300,9 @@ export default { }, }; </script> + +<style> +.max-width { + max-width: 25rem; +} +</style> diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql index db39747e94d15503abfdb0800ff15606a311b263..e782d06ba41b486db5298e50ed78158491532207 100644 --- a/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql +++ b/aleksis/apps/alsijil/frontend/components/coursebook/coursebook.graphql @@ -22,6 +22,7 @@ query documentationsForCoursebook( $objType: String $dateStart: Date! $dateEnd: Date! + $incomplete: Boolean ) { items: documentationsForCoursebook( own: $own @@ -29,6 +30,7 @@ query documentationsForCoursebook( objType: $objType dateStart: $dateStart dateEnd: $dateEnd + incomplete: $incomplete ) { id course { diff --git a/aleksis/apps/alsijil/frontend/messages/de.json b/aleksis/apps/alsijil/frontend/messages/de.json index 9d52cb9b1a9af8aeb8c182c75696a6863b274acc..614c3142e8d9d59c02b1ed79ead092690a2480b4 100644 --- a/aleksis/apps/alsijil/frontend/messages/de.json +++ b/aleksis/apps/alsijil/frontend/messages/de.json @@ -59,6 +59,7 @@ }, "filter": { "own": "Nur eigene Stunden anzeigen", + "missing": "Nur unvollständige Stunden anzeigen", "groups": "Gruppen", "courses": "Kurse", "filter_for_obj": "Nach Gruppe und Kurs filtern" diff --git a/aleksis/apps/alsijil/frontend/messages/en.json b/aleksis/apps/alsijil/frontend/messages/en.json index f5b263f76802c29262f42c22431d594e62c2a962..679044209b95c578e4e89cb439f27745b5e3f9b2 100644 --- a/aleksis/apps/alsijil/frontend/messages/en.json +++ b/aleksis/apps/alsijil/frontend/messages/en.json @@ -63,6 +63,7 @@ }, "filter": { "own": "Only show own lessons", + "missing": "Only show incomplete lessons", "groups": "Groups", "courses": "Courses", "filter_for_obj": "Filter for group and course" diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py index 5fcc55309ac13b2473beed43712797d2d68b6d8e..067818d1857c3a4054f9fbb0cc141c0fb0eae1a5 100644 --- a/aleksis/apps/alsijil/models.py +++ b/aleksis/apps/alsijil/models.py @@ -534,8 +534,9 @@ class Documentation(CalendarEvent): date_start: datetime, date_end: datetime, request: HttpRequest, - obj_type: Optional[str], - obj_id: Optional[str], + obj_type: Optional[str] = None, + obj_id: Optional[str] = None, + incomplete: Optional[bool] = False, ) -> list: """Get all the documentations for an object and a time frame. @@ -564,28 +565,35 @@ class Documentation(CalendarEvent): # 2. For each lessonEvent → check if there is a documentation # if so, add the documentation to a list, if not, create a new one - return [ - ( - existing_documentations.first() - if ( - existing_documentations := ( - event_reference_obj := event["REFERENCE_OBJECT"] - ).documentation.filter( + docs = [] + for event in events: + if incomplete and event["STATUS"] == "CANCELLED": + continue + + event_reference_obj = event["REFERENCE_OBJECT"] + existing_documentations = event_reference_obj.documentation.filter( + datetime_start=event["DTSTART"].dt, + datetime_end=event["DTEND"].dt, + ) + + if existing_documentations.exists(): + doc = existing_documentations.first() + if incomplete and doc.topic: + continue + docs.append(doc) + else: + docs.append( + cls( + pk=f"DUMMY;{event_reference_obj.id};{event['DTSTART'].dt.isoformat()};{event['DTEND'].dt.isoformat()}", + lesson_event=event_reference_obj, + course=event_reference_obj.course, + subject=event_reference_obj.subject, datetime_start=event["DTSTART"].dt, datetime_end=event["DTEND"].dt, ) - ).exists() - else cls( - pk=f"DUMMY;{event_reference_obj.id};{event['DTSTART'].dt.isoformat()};{event['DTEND'].dt.isoformat()}", - lesson_event=event_reference_obj, - course=event_reference_obj.course, - subject=event_reference_obj.subject, - datetime_start=event["DTSTART"].dt, - datetime_end=event["DTEND"].dt, ) - ) - for event in events - ] + + return docs class ParticipationStatus(ExtensibleModel): diff --git a/aleksis/apps/alsijil/schema/__init__.py b/aleksis/apps/alsijil/schema/__init__.py index afc8fd8d2c1835b69a9ace6c92d30312faaa665c..8cffee5fd320806503cacf8ee40271ef51fbdb03 100644 --- a/aleksis/apps/alsijil/schema/__init__.py +++ b/aleksis/apps/alsijil/schema/__init__.py @@ -35,6 +35,7 @@ class Query(graphene.ObjectType): obj_id=graphene.ID(required=False), date_start=graphene.Date(required=True), date_end=graphene.Date(required=True), + incomplete=graphene.Boolean(required=False), ) groups_by_person = FilterOrderList(GroupType, person=graphene.ID()) @@ -47,7 +48,15 @@ class Query(graphene.ObjectType): return documentations def resolve_documentations_for_coursebook( - root, info, own, date_start, date_end, obj_type=None, obj_id=None, **kwargs + root, + info, + own, + date_start, + date_end, + obj_type=None, + obj_id=None, + incomplete=False, + **kwargs, ): datetime_start = datetime.combine(date_start, datetime.min.time()) datetime_end = datetime.combine(date_end, datetime.max.time()) @@ -75,7 +84,7 @@ class Query(graphene.ObjectType): raise PermissionDenied() return Documentation.get_for_coursebook( - own, datetime_start, datetime_end, info.context, obj_type, obj_id + own, datetime_start, datetime_end, info.context, obj_type, obj_id, incomplete ) @staticmethod