Skip to content
Snippets Groups Projects
Commit 3c8d669c authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Merge branch...

Merge branch '300-allow-using-time-slot-numbers-in-long-term-absences-dialog-instead-of-datetimes' into 'master'

Resolve "Allow using time slot numbers in long term absences dialog (instead of datetimes)"

Closes #300

See merge request !464
parents 9e24f1ee 59e51290
No related branches found
No related tags found
1 merge request!464Resolve "Allow using time slot numbers in long term absences dialog (instead of datetimes)"
Pipeline #195667 failed
......@@ -22,32 +22,46 @@
</div>
</v-row>
<v-row>
<v-col cols="12" :sm="6" class="pl-0">
<v-col cols="12" :sm="startPeriods ? 4 : 6" class="pl-0">
<div aria-required="true">
<date-time-field
:label="$t('forms.labels.start')"
:max-date="maxStartDate"
:max-time="maxStartTime"
:limit-selectable-range="false"
:rules="$rules().required.build()"
:value="startDate"
:value="start.toISO()"
@input="handleStartDate"
/>
</div>
</v-col>
<v-col cols="12" :sm="6" class="pr-0">
<v-col cols="12" :sm="2" v-if="startPeriods" align-self="end">
<v-select
:label="$t('lesrooster.slot.period')"
:items="startPeriods"
item-text="period"
:value="startSlot"
@input="handleStartSlot"
return-object
/>
</v-col>
<v-col cols="12" :sm="endPeriods ? 4 : 6" class="pr-0">
<div aria-required="true">
<date-time-field
:label="$t('forms.labels.end')"
:min-date="minEndDate"
:min-time="minEndTime"
:limit-selectable-range="false"
:rules="$rules().required.build()"
:value="endDate"
:value="end.toISO()"
@input="handleEndDate"
/>
</div>
</v-col>
<v-col cols="12" :sm="2" v-if="endPeriods" align-self="end">
<v-select
:label="$t('lesrooster.slot.period')"
:items="endPeriods"
item-text="period"
:value="endSlot"
@input="handleEndSlot"
return-object
/>
</v-col>
</v-row>
<v-row>
<v-text-field
......@@ -76,7 +90,7 @@
import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReasonGroupSelect.vue";
import DateTimeField from "aleksis.core/components/generic/forms/DateTimeField.vue";
import PersonField from "aleksis.core/components/generic/forms/PersonField.vue";
import { gqlPersons } from "./absenceCreation.graphql";
import { gqlPersons, periodsByDay } from "./absenceCreation.graphql";
import formRulesMixin from "aleksis.core/mixins/formRulesMixin.js";
import { DateTime } from "luxon";
......@@ -96,10 +110,14 @@ export default {
"comment",
"absence-reason",
],
data() {
return {
gqlQuery: gqlPersons,
};
apollo: {
periodsByDay: {
query: periodsByDay,
result(_) {
this.handleStartDate(this.start.toISO());
this.handleEndDate(this.end.toISO());
},
},
},
props: {
persons: {
......@@ -127,60 +145,98 @@ export default {
required: true,
},
},
data() {
return {
gqlQuery: gqlPersons,
startDT: DateTime.fromISO(this.startDate),
endDT: DateTime.fromISO(this.endDate),
startPeriods: false,
endPeriods: false,
startSlot: undefined,
endSlot: undefined,
};
},
computed: {
maxStartTime() {
// Only if on the same day
const start = DateTime.fromISO(this.startDate);
const end = DateTime.fromISO(this.endDate);
if (start.day !== end.day) return;
return end.minus({ minutes: 5 }).toFormat("HH:mm");
},
minEndTime() {
// Only if on the same day
const start = DateTime.fromISO(this.startDate);
const end = DateTime.fromISO(this.endDate);
if (start.day !== end.day) return;
return start.plus({ minutes: 5 }).toFormat("HH:mm");
start: {
get() {
return this.startDT;
},
set(dt) {
this.startDT = dt;
if (dt >= this.end) {
this.end = dt.plus({ minutes: 5 });
}
this.$emit("start-date", dt.toISO());
},
},
maxStartDate() {
const end = DateTime.fromISO(this.endDate);
return end.toISODate();
},
minEndDate() {
const start = DateTime.fromISO(this.startDate);
return start.toISODate();
end: {
get() {
return this.endDT;
},
set(dt) {
this.endDT = dt;
if (dt <= this.start) {
this.start = dt.minus({ minutes: 5 });
}
this.$emit("end-date", dt.toISO());
},
},
},
methods: {
handleStartDate(startDate) {
const parsedStart = DateTime.fromISO(startDate);
const parsedEnd = DateTime.fromISO(this.endDate);
if (parsedStart >= parsedEnd) {
this.$emit(
"end-date",
parsedStart.plus({ minutes: 5 }).toISO({ suppressSeconds: true }),
getPeriodsForWeekday(weekday) {
// Adapt from python conventions
const pythonWeekday = weekday - 1;
let periodsForWeekday = this.periodsByDay.find(
(period) => period.weekday === pythonWeekday,
);
if (!periodsForWeekday) return false;
return periodsForWeekday.periods;
},
handleStartDate(date) {
this.start = DateTime.fromISO(date);
if (this.periodsByDay && this.periodsByDay.length > 0) {
// Select periods for day
this.startPeriods = this.getPeriodsForWeekday(this.start.weekday);
if (!this.startPeriods) return;
// Sync PeriodSelect
const startTime = this.start.toFormat("HH:mm:ss");
this.startSlot = this.startPeriods.find(
(period) => period.timeStart === startTime,
);
}
this.$emit("start-date", startDate);
this.$refs.form.resetValidation();
this.$refs.form.validate();
},
handleEndDate(endDate) {
const parsedStart = DateTime.fromISO(this.startDate);
const parsedEnd = DateTime.fromISO(endDate);
if (parsedEnd <= parsedStart) {
this.$emit(
"start-date",
parsedEnd.minus({ minutes: 5 }).toISO({ suppressSeconds: true }),
handleEndDate(date) {
this.end = DateTime.fromISO(date);
if (this.periodsByDay && this.periodsByDay.length > 0) {
// Select periods for day
this.endPeriods = this.getPeriodsForWeekday(this.end.weekday);
if (!this.endPeriods) return;
// Sync PeriodSelect
const endTime = this.end.toFormat("HH:mm:ss");
this.endSlot = this.endPeriods.find(
(period) => period.endTime === endTime,
);
}
this.$emit("end-date", endDate);
this.$refs.form.resetValidation();
this.$refs.form.validate();
},
handleStartSlot(slot) {
// Sync TimeSelect
const startTime = DateTime.fromISO(slot.timeStart);
this.start = this.start.set({
hour: startTime.hour,
minute: startTime.minute,
second: startTime.second,
});
},
handleEndSlot(slot) {
// Sync TimeSelect
const endTime = DateTime.fromISO(slot.timeEnd);
this.end = this.end.set({
hour: endTime.hour,
minute: endTime.minute,
second: endTime.second,
});
},
},
};
......
......@@ -7,6 +7,17 @@ query gqlPersons {
}
}
query periodsByDay {
periodsByDay: periodsByDay {
weekday
periods {
period
timeStart
timeEnd
}
}
}
query lessonsForPersons($persons: [ID]!, $start: DateTime!, $end: DateTime!) {
items: lessonsForPersons(persons: $persons, start: $start, end: $end) {
id
......
from collections import defaultdict
from datetime import datetime
from django.apps import apps
from django.db.models import BooleanField, ExpressionWrapper, Q
import graphene
......@@ -53,6 +55,17 @@ from .personal_note import (
from .statistics import StatisticsByPersonType
class PeriodType(graphene.ObjectType):
period = graphene.Int()
time_start = graphene.Time()
time_end = graphene.Time()
class WeekdayType(graphene.ObjectType):
weekday = graphene.Int()
periods = graphene.List(PeriodType)
class Query(graphene.ObjectType):
documentations_by_course_id = FilterOrderList(
DocumentationType, course_id=graphene.ID(required=True)
......@@ -100,6 +113,8 @@ class Query(graphene.ObjectType):
group=graphene.ID(required=True),
)
periods_by_day = graphene.List(WeekdayType)
def resolve_documentations_by_course_id(root, info, course_id, **kwargs):
documentations = Documentation.objects.filter(
pk__in=Documentation.objects.filter(course_id=course_id)
......@@ -347,6 +362,35 @@ class Query(graphene.ObjectType):
annotate_person_statistics_for_school_term(members, school_term, group=group), info
)
@staticmethod
def resolve_periods_by_day(root, info):
if apps.is_installed("aleksis.apps.lesrooster"):
Slot = apps.get_model("lesrooster", "Slot")
ValidityRange = apps.get_model("lesrooster", "ValidityRange")
slots = (
Slot.objects.filter(
time_grid__validity_range=ValidityRange.current, period__isnull=False
)
.order_by("weekday")
.values("weekday", "period", "time_start", "time_end")
)
# Key by weekday
by_weekday = defaultdict(list)
for slot in slots:
# return nested dicts: {weekday periods { period time_* }}
# sort periods by period
by_weekday[slot["weekday"]].append(slot)
# Nest and sort periods
periods = []
for weekday, slots in by_weekday.items():
periods.append(
{"weekday": weekday, "periods": sorted(slots, key=lambda slot: slot["period"])}
)
return periods
else:
return []
class Mutation(graphene.ObjectType):
create_or_update_documentations = DocumentationBatchCreateOrUpdateMutation.Field()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment