From 1e7d1d838e18efaa93baba17cd0a7164ca6df7b4 Mon Sep 17 00:00:00 2001 From: Hangzhi Yu <hangzhi@protonmail.com> Date: Thu, 3 Aug 2023 13:01:45 +0200 Subject: [PATCH] Reformat --- .../lesrooster/frontend/components/Break.vue | 8 +- .../frontend/components/LesroosterSlot.vue | 121 +++----- .../TimeboundCourseConfigCRUDTable.vue | 109 ++++--- .../TimeboundCourseConfigRaster.vue | 241 ++++++++++----- .../frontend/components/ValidityRange.vue | 67 +++-- .../components/ValidityRangeField.vue | 66 ++-- .../frontend/components/break.graphql | 126 ++++---- .../frontend/components/helper.graphql | 78 ++--- .../components/lesson_raster/LessonRaster.vue | 284 ++++++++++-------- .../components/lesson_raster/SlotCard.vue | 56 ++-- .../components/lesson_raster/SlotCreator.vue | 166 +++++----- .../frontend/components/slot.graphql | 184 ++++++------ .../components/timeboundCourseConfig.graphql | 18 +- .../timetable_management/LessonCard.vue | 12 +- .../TimetableManagement.vue | 145 ++++----- .../timetableManagement.graphql | 8 +- aleksis/apps/lesrooster/frontend/index.js | 178 +++++------ .../apps/lesrooster/frontend/messages/de.json | 4 +- .../apps/lesrooster/frontend/messages/en.json | 2 +- aleksis/apps/lesrooster/models.py | 4 +- aleksis/apps/lesrooster/schema/__init__.py | 25 +- aleksis/apps/lesrooster/schema/break_type.py | 16 +- aleksis/apps/lesrooster/schema/lesson.py | 9 +- aleksis/apps/lesrooster/schema/slot.py | 31 +- .../schema/timebound_course_config.py | 6 +- .../apps/lesrooster/schema/validity_range.py | 8 +- 26 files changed, 1061 insertions(+), 911 deletions(-) diff --git a/aleksis/apps/lesrooster/frontend/components/Break.vue b/aleksis/apps/lesrooster/frontend/components/Break.vue index 8a79c146..e73eec41 100644 --- a/aleksis/apps/lesrooster/frontend/components/Break.vue +++ b/aleksis/apps/lesrooster/frontend/components/Break.vue @@ -21,7 +21,7 @@ export default { { text: this.$t("lesrooster.validity_range.title"), value: "validityRange", - orderKey: "validity_range__date_start" + orderKey: "validity_range__date_start", }, { text: this.$t("lesrooster.slot.weekday"), @@ -58,11 +58,11 @@ export default { periodAfter: item.period, weekday: this.weekdayAsInt(item.weekday), validityRange: item.validityRange.id, - } + }; }, getPatchData(items) { console.log("patch items", items); - return items.map(item => ({ + return items.map((item) => ({ id: item.id, name: item.name, weekday: this.weekdayAsInt(item.weekday), @@ -71,7 +71,7 @@ export default { timeEnd: item.timeEnd, validityRange: item.validityRange.id, })); - } + }, }, }; </script> diff --git a/aleksis/apps/lesrooster/frontend/components/LesroosterSlot.vue b/aleksis/apps/lesrooster/frontend/components/LesroosterSlot.vue index 7367bae0..6ca03410 100644 --- a/aleksis/apps/lesrooster/frontend/components/LesroosterSlot.vue +++ b/aleksis/apps/lesrooster/frontend/components/LesroosterSlot.vue @@ -3,34 +3,30 @@ import InlineCRUDList from "aleksis.core/components/generic/InlineCRUDList.vue"; import WeekDayField from "aleksis.core/components/generic/forms/WeekDayField.vue"; import PositiveSmallIntegerField from "aleksis.core/components/generic/forms/PositiveSmallIntegerField.vue"; import TimeField from "aleksis.core/components/generic/forms/TimeField.vue"; -import ValidityRangeField from "./ValidityRangeField.vue";</script> +import ValidityRangeField from "./ValidityRangeField.vue"; +</script> <template> <inline-c-r-u-d-list - :headers="headers" - :i18n-key="i18nKey" - :create-item-i18n-key="createItemI18nKey" - :gql-query="gqlQuery" - :gql-create-mutation="gqlCreateMutation" - :gql-patch-mutation="gqlPatchMutation" - :gql-delete-mutation="gqlDeleteMutation" - :gql-delete-multiple-mutation="gqlDeleteMultipleMutation" - :default-item="defaultItem" - :get-create-data="getCreateData" - :get-patch-data="getPatchData" - filter + :headers="headers" + :i18n-key="i18nKey" + :create-item-i18n-key="createItemI18nKey" + :gql-query="gqlQuery" + :gql-create-mutation="gqlCreateMutation" + :gql-patch-mutation="gqlPatchMutation" + :gql-delete-mutation="gqlDeleteMutation" + :gql-delete-multiple-mutation="gqlDeleteMultipleMutation" + :default-item="defaultItem" + :get-create-data="getCreateData" + :get-patch-data="getPatchData" + filter > <template #weekday="{ item }"> {{ $t("weekdays." + item.weekday) }} </template> <template #weekday.field="{ attrs, on }"> <div aria-required="true"> - <week-day-field - v-bind="attrs" - v-on="on" - :rules="required" - required - /> + <week-day-field v-bind="attrs" v-on="on" :rules="required" required /> </div> </template> @@ -49,10 +45,7 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> </template> <template #period.field="{ attrs, on }"> - <positive-small-integer-field - v-bind="attrs" - v-on="on" - /> + <positive-small-integer-field v-bind="attrs" v-on="on" /> </template> <template #timeStart="{ item }"> @@ -60,12 +53,7 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> </template> <template #timeStart.field="{ attrs, on }"> <div aria-required="true"> - <time-field - v-bind="attrs" - v-on="on" - :rules="required" - required - /> + <time-field v-bind="attrs" v-on="on" :rules="required" required /> </div> </template> @@ -74,22 +62,17 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> </template> <template #timeEnd.field="{ attrs, on }"> <div aria-required="true"> - <time-field - v-bind="attrs" - v-on="on" - :rules="required" - required - /> + <time-field v-bind="attrs" v-on="on" :rules="required" required /> </div> </template> <template #filters="{ attrs, on }"> <week-day-field - v-bind="attrs('weekday')" - v-on="on('weekday')" - return-int - clearable - :label="$t('lesrooster.slot.weekday')" + v-bind="attrs('weekday')" + v-on="on('weekday')" + return-int + clearable + :label="$t('lesrooster.slot.weekday')" /> <v-row> @@ -98,7 +81,7 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> v-bind="attrs('period__gte')" v-on="on('period__gte')" :label="$t('lesrooster.slot.period_gte')" - /> + /> </v-col> <v-col> @@ -106,25 +89,24 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> v-bind="attrs('period__lte')" v-on="on('period__lte')" :label="$t('lesrooster.slot.period_lte')" - /> + /> </v-col> </v-row> <v-row> <v-col> <time-field - v-bind="attrs('time_end__gte')" - v-on="on('time_end__gte')" - :label="$t('school_term.after')" - /> + v-bind="attrs('time_end__gte')" + v-on="on('time_end__gte')" + :label="$t('school_term.after')" + /> </v-col> <v-col> - - <time-field - v-bind="attrs('time_start__lte')" - v-on="on('time_start__lte')" - :label="$t('school_term.before')" - /> + <time-field + v-bind="attrs('time_start__lte')" + v-on="on('time_start__lte')" + :label="$t('school_term.before')" + /> </v-col> </v-row> </template> @@ -140,9 +122,7 @@ import { updateSlots, } from "./slot.graphql"; -import { - currentValidityRange as gqlCurrentValidityRange -} from "./validityRange.graphql" +import { currentValidityRange as gqlCurrentValidityRange } from "./validityRange.graphql"; export default { name: "LesroosterSlot", @@ -156,7 +136,7 @@ export default { { text: this.$t("lesrooster.validity_range.title"), value: "validityRange", - orderKey: "validity_range__date_start" + orderKey: "validity_range__date_start", }, { text: this.$t("lesrooster.slot.weekday"), @@ -192,24 +172,19 @@ export default { name: "", }, }, - required: [ - value => !!value || this.$t("forms.errors.required"), - ] + required: [(value) => !!value || this.$t("forms.errors.required")], }; }, methods: { weekdayAsInt(weekday) { // Weekday is in format A_0 (monday) to A_6 if ( - ( - weekday instanceof String || - typeof weekday === "string" - ) && - weekday.length === 3 && - weekday.startsWith("A_") && - !isNaN(parseInt(weekday.charAt(2))) + (weekday instanceof String || typeof weekday === "string") && + weekday.length === 3 && + weekday.startsWith("A_") && + !isNaN(parseInt(weekday.charAt(2))) ) { - return parseInt(weekday.charAt(2)) + return parseInt(weekday.charAt(2)); } console.error("Invalid Weekday:", weekday); return NaN; @@ -220,11 +195,11 @@ export default { ...item, weekday: this.weekdayAsInt(item.weekday), validityRange: item.validityRange.id, - } + }; }, getPatchData(items) { console.log("patch items", items); - return items.map(item => ({ + return items.map((item) => ({ id: item.id, name: item.name, weekday: this.weekdayAsInt(item.weekday), @@ -233,16 +208,16 @@ export default { timeEnd: item.timeEnd, validityRange: item.validityRange.id, })); - } + }, }, apollo: { currentValidityRange: { query: gqlCurrentValidityRange, result({ data }) { this.$set(this.defaultItem, "validityRange", data.currentValidityRange); - } - } - } + }, + }, + }, }; </script> diff --git a/aleksis/apps/lesrooster/frontend/components/TimeboundCourseConfigCRUDTable.vue b/aleksis/apps/lesrooster/frontend/components/TimeboundCourseConfigCRUDTable.vue index 9b392c10..391f6499 100644 --- a/aleksis/apps/lesrooster/frontend/components/TimeboundCourseConfigCRUDTable.vue +++ b/aleksis/apps/lesrooster/frontend/components/TimeboundCourseConfigCRUDTable.vue @@ -3,21 +3,22 @@ import InlineCRUDList from "aleksis.core/components/generic/InlineCRUDList.vue"; import WeekDayField from "aleksis.core/components/generic/forms/WeekDayField.vue"; import PositiveSmallIntegerField from "aleksis.core/components/generic/forms/PositiveSmallIntegerField.vue"; import TimeField from "aleksis.core/components/generic/forms/TimeField.vue"; -import ValidityRangeField from "./ValidityRangeField.vue";</script> +import ValidityRangeField from "./ValidityRangeField.vue"; +</script> <template> <inline-c-r-u-d-list - :headers="headers" - :i18n-key="i18nKey" - :create-item-i18n-key="createItemI18nKey" - :gql-query="gqlQuery" - :gql-create-mutation="gqlCreateMutation" - :gql-patch-mutation="gqlPatchMutation" - :gql-delete-mutation="gqlDeleteMutation" - :default-item="defaultItem" - :get-create-data="getCreateData" - :get-patch-data="getPatchData" - filter + :headers="headers" + :i18n-key="i18nKey" + :create-item-i18n-key="createItemI18nKey" + :gql-query="gqlQuery" + :gql-create-mutation="gqlCreateMutation" + :gql-patch-mutation="gqlPatchMutation" + :gql-delete-mutation="gqlDeleteMutation" + :default-item="defaultItem" + :get-create-data="getCreateData" + :get-patch-data="getPatchData" + filter > <template #course="{ item }"> {{ item.course.name }} @@ -52,23 +53,20 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> {{ item.validityRange?.name }} </template> <template #validityRange.field="{ attrs, on }"> - <validity-range-field - v-bind="attrs" - v-on="on" - :rules="required" - /> + <validity-range-field v-bind="attrs" v-on="on" :rules="required" /> </template> <template #scheduledSlotCount.field="{ attrs, on }"> <positive-small-integer-field - v-bind="attrs" - v-on="on" - :rules="required" + v-bind="attrs" + v-on="on" + :rules="required" /> </template> <template #teachers="{ item }"> - <v-chip v-for="teacher in item.teachers">{{ teacher.fullName }}</v-chip> + <v-chip v-for="teacher in item.teachers">{{ teacher.fullName }}</v-chip + > </template> <template #teachers.field="{ attrs, on }"> <v-autocomplete @@ -86,11 +84,11 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> <template #filters="{ attrs, on }"> <week-day-field - v-bind="attrs('weekday')" - v-on="on('weekday')" - return-int - clearable - :label="$t('lesrooster.slot.weekday')" + v-bind="attrs('weekday')" + v-on="on('weekday')" + return-int + clearable + :label="$t('lesrooster.slot.weekday')" /> <v-row> @@ -99,7 +97,7 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> v-bind="attrs('period__gte')" v-on="on('period__gte')" :label="$t('lesrooster.slot.period_gte')" - /> + /> </v-col> <v-col> @@ -107,25 +105,24 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> v-bind="attrs('period__lte')" v-on="on('period__lte')" :label="$t('lesrooster.slot.period_lte')" - /> + /> </v-col> </v-row> <v-row> <v-col> <time-field - v-bind="attrs('time_end__gte')" - v-on="on('time_end__gte')" - :label="$t('school_term.after')" - /> + v-bind="attrs('time_end__gte')" + v-on="on('time_end__gte')" + :label="$t('school_term.after')" + /> </v-col> <v-col> - - <time-field - v-bind="attrs('time_start__lte')" - v-on="on('time_start__lte')" - :label="$t('school_term.before')" - /> + <time-field + v-bind="attrs('time_start__lte')" + v-on="on('time_start__lte')" + :label="$t('school_term.before')" + /> </v-col> </v-row> </template> @@ -140,14 +137,9 @@ import { updateTimeboundCourseConfigs, } from "./timeboundCourseConfig.graphql"; -import { - currentValidityRange as gqlCurrentValidityRange -} from "./validityRange.graphql" +import { currentValidityRange as gqlCurrentValidityRange } from "./validityRange.graphql"; -import { - gqlPersons, - gqlCourses, -} from "./helper.graphql"; +import { gqlPersons, gqlCourses } from "./helper.graphql"; export default { name: "TimeboungCourseConfigCRUDTable", @@ -161,19 +153,22 @@ export default { { text: this.$t("lesrooster.validity_range.title"), value: "validityRange", - orderKey: "validity_range__date_start" + orderKey: "validity_range__date_start", }, { text: this.$t("lesrooster.timebound_course_config.teachers"), value: "teachers", }, { - text: this.$t("lesrooster.timebound_course_config.scheduled_slot_count"), + text: this.$t( + "lesrooster.timebound_course_config.scheduled_slot_count" + ), value: "scheduledSlotCount", }, - ], + ], i18nKey: "lesrooster.timebound_course_config", - createItemI18nKey: "lesrooster.timebound_course_config.create_timebound_course_config", + createItemI18nKey: + "lesrooster.timebound_course_config.create_timebound_course_config", gqlQuery: timeboundCourseConfigs, gqlCreateMutation: createTimeboundCourseConfig, gqlPatchMutation: updateTimeboundCourseConfigs, @@ -190,9 +185,7 @@ export default { teachers: [], scheduledSlotCount: undefined, }, - required: [ - value => !!value || this.$t("forms.errors.required"), - ] + required: [(value) => !!value || this.$t("forms.errors.required")], }; }, methods: { @@ -201,27 +194,27 @@ export default { return { ...item, course: item.course.id, - teachers: item.teachers.map(t => t.id), + teachers: item.teachers.map((t) => t.id), validityRange: item.validityRange.id, - } + }; }, getPatchData(items) { console.log("patch items", items); - return items.map(item => ({ + return items.map((item) => ({ id: item.id, course: item.course.id, - teachers: item.teachers.map(t => t.id), + teachers: item.teachers.map((t) => t.id), validityRange: item.validityRange.id, scheduledSlotCount: item.scheduledSlotCount, })); - } + }, }, apollo: { currentValidityRange: { query: gqlCurrentValidityRange, result({ data }) { this.$set(this.defaultItem, "validityRange", data.currentValidityRange); - } + }, }, persons: gqlPersons, courses: gqlCourses, diff --git a/aleksis/apps/lesrooster/frontend/components/TimeboundCourseConfigRaster.vue b/aleksis/apps/lesrooster/frontend/components/TimeboundCourseConfigRaster.vue index b457a6f4..f7aae46c 100644 --- a/aleksis/apps/lesrooster/frontend/components/TimeboundCourseConfigRaster.vue +++ b/aleksis/apps/lesrooster/frontend/components/TimeboundCourseConfigRaster.vue @@ -3,7 +3,8 @@ import WeekDayField from "aleksis.core/components/generic/forms/WeekDayField.vue import PositiveSmallIntegerField from "aleksis.core/components/generic/forms/PositiveSmallIntegerField.vue"; import TimeField from "aleksis.core/components/generic/forms/TimeField.vue"; import SaveButton from "aleksis.core/components/generic/buttons/SaveButton.vue"; -import ValidityRangeField from "./ValidityRangeField.vue";</script> +import ValidityRangeField from "./ValidityRangeField.vue"; +</script> <template> <div> @@ -16,9 +17,7 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> :items="tableItems" > <template #top> - <v-toolbar - flat - > + <v-toolbar flat> <validity-range-field solo rounded @@ -41,13 +40,11 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> class="mt-8" /> <v-spacer></v-spacer> - <v-divider - class="mx-4" - inset - vertical - ></v-divider> + <v-divider class="mx-4" inset vertical></v-divider> <save-button - :disabled="!editedCourseConfigs.length && !createdCourseConfigs.length" + :disabled=" + !editedCourseConfigs.length && !createdCourseConfigs.length + " @click="save" /> </v-toolbar> @@ -56,12 +53,7 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> <template #item.subject="{ item, value }"> <v-tooltip bottom> <template v-slot:activator="{ on, attrs }"> - <v-chip - :color="value.colourFg" - v-on="on" - v-bind="attrs" - outlined - > + <v-chip :color="value.colourFg" v-on="on" v-bind="attrs" outlined> {{ value.shortName }} </v-chip> </template> @@ -69,7 +61,10 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> </v-tooltip> </template> - <template v-for="header in groupHeaders" #[tableItemSlotName(header)]="{ item, value }"> + <template + v-for="header in groupHeaders" + #[tableItemSlotName(header)]="{ item, value }" + > <template v-for="(course, index) in value"> <v-row no-gutters class="mt-2"> <v-col cols="6"> @@ -78,9 +73,18 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> filled class="mx-1" :disabled="loading" - :value="getCurrentCourseConfig(course) ? getCurrentCourseConfig(course).scheduledSlotCount : course.lessonQuota" - :label="$t('lesrooster.timebound_course_config.scheduled_slot_count')" - @input="event => setCourseConfigData(course, {scheduledSlotCount: event})" + :value=" + getCurrentCourseConfig(course) + ? getCurrentCourseConfig(course).scheduledSlotCount + : course.lessonQuota + " + :label=" + $t('lesrooster.timebound_course_config.scheduled_slot_count') + " + @input=" + (event) => + setCourseConfigData(course, { scheduledSlotCount: event }) + " /> </v-col> <v-col cols="6"> @@ -95,20 +99,41 @@ import ValidityRangeField from "./ValidityRangeField.vue";</script> class="mx-1" :disabled="loading" :label="$t('lesrooster.timebound_course_config.teachers')" - :value="getCurrentCourseConfig(course) ? getCurrentCourseConfig(course).teachers : course.teachers" - @input="event => setCourseConfigData(course, {teachers: event})" + :value=" + getCurrentCourseConfig(course) + ? getCurrentCourseConfig(course).teachers + : course.teachers + " + @input=" + (event) => setCourseConfigData(course, { teachers: event }) + " > <template #item="data"> <template v-if="typeof data.item !== 'object'"> - <v-list-item-content v-text="data.item"></v-list-item-content> + <v-list-item-content + v-text="data.item" + ></v-list-item-content> </template> <template v-else> <v-list-item-action> - <v-checkbox v-model="data.attrs.inputValue"/> + <v-checkbox v-model="data.attrs.inputValue" /> </v-list-item-action> <v-list-item-content> - <v-list-item-title v-html="data.item.fullName"></v-list-item-title> - <v-list-item-subtitle v-if="data.item.lessonQuota" v-html="$t('lesrooster.timebound_course_config.lessons_planned', { planned: getPlannedLessons(data.item.id), quota: data.item.lessonQuota })"></v-list-item-subtitle> + <v-list-item-title + v-html="data.item.fullName" + ></v-list-item-title> + <v-list-item-subtitle + v-if="data.item.lessonQuota" + v-html=" + $t( + 'lesrooster.timebound_course_config.lessons_planned', + { + planned: getPlannedLessons(data.item.id), + quota: data.item.lessonQuota, + } + ) + " + ></v-list-item-subtitle> </v-list-item-content> </template> </template> @@ -130,21 +155,17 @@ import { updateTimeboundCourseConfigs, } from "./timeboundCourseConfig.graphql"; -import { - currentValidityRange as gqlCurrentValidityRange -} from "./validityRange.graphql"; +import { currentValidityRange as gqlCurrentValidityRange } from "./validityRange.graphql"; -import { - gqlClasses, - gqlTeachers, -} from "./helper.graphql"; +import { gqlClasses, gqlTeachers } from "./helper.graphql"; export default { name: "TimeboungCourseConfigRaster", data() { return { i18nKey: "lesrooster.timebound_course_config", - createItemI18nKey: "lesrooster.timebound_course_config.create_timebound_course_config", + createItemI18nKey: + "lesrooster.timebound_course_config.create_timebound_course_config", defaultItem: { course: { id: "", @@ -157,9 +178,7 @@ export default { teachers: [], scheduledSlotCount: undefined, }, - required: [ - value => !!value || this.$t("forms.errors.required"), - ], + required: [(value) => !!value || this.$t("forms.errors.required")], internalValidityRange: null, groups: [], selectedGroups: [], @@ -176,26 +195,48 @@ export default { return "item." + header.value; }, getCurrentCourseConfig(course) { - let currentCourseConfigs = course.lrTimeboundCourseConfigs.filter((timeboundConfig) => timeboundConfig.validityRange.id === this.internalValidityRange.id); - if (course.lrTimeboundCourseConfigs.length && currentCourseConfigs.length) { + let currentCourseConfigs = course.lrTimeboundCourseConfigs.filter( + (timeboundConfig) => + timeboundConfig.validityRange.id === this.internalValidityRange.id + ); + if ( + course.lrTimeboundCourseConfigs.length && + currentCourseConfigs.length + ) { return currentCourseConfigs[0]; } else { return null; } }, setCourseConfigData(course, newValue) { - if (!(course.lrTimeboundCourseConfigs.filter(c => c.validityRange.id === this.internalValidityRange?.id).length)) { - let existingCreatedCourseConfig = this.createdCourseConfigs.find(c => c.course === course.id && c.validityRange === this.internalValidityRange?.id); - if (!(existingCreatedCourseConfig)) { - this.createdCourseConfigs.push({course: course.id, validityRange: this.internalValidityRange?.id, teachers: course.teachers.map(t => t.id), scheduledSlotCount: course.lessonQuota, ...newValue}); + if ( + !course.lrTimeboundCourseConfigs.filter( + (c) => c.validityRange.id === this.internalValidityRange?.id + ).length + ) { + let existingCreatedCourseConfig = this.createdCourseConfigs.find( + (c) => + c.course === course.id && + c.validityRange === this.internalValidityRange?.id + ); + if (!existingCreatedCourseConfig) { + this.createdCourseConfigs.push({ + course: course.id, + validityRange: this.internalValidityRange?.id, + teachers: course.teachers.map((t) => t.id), + scheduledSlotCount: course.lessonQuota, + ...newValue, + }); } else { Object.assign(existingCreatedCourseConfig, newValue); } } else { let courseConfigID = course.lrTimeboundCourseConfigs[0].id; - let existingEditedCourseConfig = this.editedCourseConfigs.find(c => c.id === courseConfigID) - if (!(existingEditedCourseConfig)) { - this.editedCourseConfigs.push({id: courseConfigID, ...newValue}) + let existingEditedCourseConfig = this.editedCourseConfigs.find( + (c) => c.id === courseConfigID + ); + if (!existingEditedCourseConfig) { + this.editedCourseConfigs.push({ id: courseConfigID, ...newValue }); } else { Object.assign(existingEditedCourseConfig, newValue); } @@ -204,17 +245,25 @@ export default { save() { this.loading = true; - for (let mutationCombination of [{ data: this.editedCourseConfigs, mutation: updateTimeboundCourseConfigs }, { data: this.createdCourseConfigs, mutation: batchCreateTimeboundCourseConfig }]) { + for (let mutationCombination of [ + { + data: this.editedCourseConfigs, + mutation: updateTimeboundCourseConfigs, + }, + { + data: this.createdCourseConfigs, + mutation: batchCreateTimeboundCourseConfig, + }, + ]) { if (mutationCombination.data.length) { this.$apollo .mutate({ mutation: mutationCombination.mutation, variables: { - input: mutationCombination.data + input: mutationCombination.data, }, }) - .catch((error) => { - }); + .catch((error) => {}); } } @@ -225,64 +274,100 @@ export default { }, getTeacherList(subjectTeachers) { return [ - { header: this.$t("lesrooster.timebound_course_config.subject_teachers") }, - ...this.persons.filter(person => subjectTeachers.find(teacher => teacher.id === person.id)), + { + header: this.$t( + "lesrooster.timebound_course_config.subject_teachers" + ), + }, + ...this.persons.filter((person) => + subjectTeachers.find((teacher) => teacher.id === person.id) + ), { divider: true }, { header: this.$t("lesrooster.timebound_course_config.all_teachers") }, - ...this.persons.filter(person => !subjectTeachers.find(teacher => teacher.id === person.id)), + ...this.persons.filter( + (person) => + !subjectTeachers.find((teacher) => teacher.id === person.id) + ), ]; - } + }, }, computed: { groupIDList() { - return this.selectedGroups.map(group => group.id); + return this.selectedGroups.map((group) => group.id); }, subjectGroupCombinations() { - return [].concat.apply([], this.items.map(subject => Object.keys(subject.groupCombinations))); + return [].concat.apply( + [], + this.items.map((subject) => Object.keys(subject.groupCombinations)) + ); }, groupHeaders() { - return this.selectedGroups.map(group => ({text: group.shortName, value: JSON.stringify([group.id])})).concat(this.subjectGroupCombinations.map(combination => { - let parsedCombination = JSON.parse(combination); - return { - text: parsedCombination.map(groupID => this.groups.find(group => group.id === groupID).shortName).join(", "), value: combination - }; - })).filter((obj, index, self) => index === self.findIndex((o) => o.value === obj.value)) + return this.selectedGroups + .map((group) => ({ + text: group.shortName, + value: JSON.stringify([group.id]), + })) + .concat( + this.subjectGroupCombinations.map((combination) => { + let parsedCombination = JSON.parse(combination); + return { + text: parsedCombination + .map( + (groupID) => + this.groups.find((group) => group.id === groupID).shortName + ) + .join(", "), + value: combination, + }; + }) + ) + .filter( + (obj, index, self) => + index === self.findIndex((o) => o.value === obj.value) + ); }, headers() { - let groupHeadersWithWidth = this.groupHeaders.map(header => ({ ...header, width: `${95/this.groupHeaders.length}%` })); - return [{ - text: this.$t("lesrooster.timebound_course_config.subject"), - value: "subject", - width: "5%", - }].concat(groupHeadersWithWidth); + let groupHeadersWithWidth = this.groupHeaders.map((header) => ({ + ...header, + width: `${95 / this.groupHeaders.length}%`, + })); + return [ + { + text: this.$t("lesrooster.timebound_course_config.subject"), + value: "subject", + width: "5%", + }, + ].concat(groupHeadersWithWidth); }, items() { - return this.subjects.map(subject => { + return this.subjects.map((subject) => { let groupCombinations = {}; - subject.courses.forEach(course => { - let groupIds = JSON.stringify(course.groups.map(group => group.id).sort()); + subject.courses.forEach((course) => { + let groupIds = JSON.stringify( + course.groups.map((group) => group.id).sort() + ); if (!groupCombinations[groupIds]) { groupCombinations[groupIds] = []; } - if (!(groupCombinations[groupIds].find(c => c.id === course.id))) { + if (!groupCombinations[groupIds].find((c) => c.id === course.id)) { groupCombinations[groupIds].push({ - ...course + ...course, }); } }); - subject = { ...subject, groupCombinations: {...groupCombinations} }; + subject = { ...subject, groupCombinations: { ...groupCombinations } }; return subject; }); }, tableItems() { - return this.items.map(subject => { + return this.items.map((subject) => { let { courses, groupCombinations, ...reducedSubject } = subject; - return {subject: reducedSubject, ...subject.groupCombinations}; + return { subject: reducedSubject, ...subject.groupCombinations }; }); }, }, @@ -291,13 +376,13 @@ export default { query: gqlCurrentValidityRange, result(data) { this.internalValidityRange = data.data.currentValidityRange; - } + }, }, groups: { query: gqlClasses, result(data) { this.selectedGroups = data.data.groups; - } + }, }, subjects: { query: subjects, diff --git a/aleksis/apps/lesrooster/frontend/components/ValidityRange.vue b/aleksis/apps/lesrooster/frontend/components/ValidityRange.vue index f8ab59a7..b1cfb722 100644 --- a/aleksis/apps/lesrooster/frontend/components/ValidityRange.vue +++ b/aleksis/apps/lesrooster/frontend/components/ValidityRange.vue @@ -1,22 +1,23 @@ <script setup> import InlineCRUDList from "aleksis.core/components/generic/InlineCRUDList.vue"; import DateField from "aleksis.core/components/generic/forms/DateField.vue"; -import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField.vue";</script> +import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField.vue"; +</script> <template> <inline-c-r-u-d-list - :headers="headers" - :i18n-key="i18nKey" - create-item-i18n-key="lesrooster.validity_range.create_validity_range" - :gql-query="gqlQuery" - :gql-create-mutation="gqlCreateMutation" - :gql-patch-mutation="gqlPatchMutation" - :gql-delete-mutation="gqlDeleteMutation" - :gql-delete-multiple-mutation="gqlDeleteMultipleMutation" - :default-item="defaultItem" - :get-create-data="getCreateData" - :get-patch-data="getPatchData" - filter + :headers="headers" + :i18n-key="i18nKey" + create-item-i18n-key="lesrooster.validity_range.create_validity_range" + :gql-query="gqlQuery" + :gql-create-mutation="gqlCreateMutation" + :gql-patch-mutation="gqlPatchMutation" + :gql-delete-mutation="gqlDeleteMutation" + :gql-delete-multiple-mutation="gqlDeleteMultipleMutation" + :default-item="defaultItem" + :get-create-data="getCreateData" + :get-patch-data="getPatchData" + filter > <template #schoolTerm="{ item }"> {{ item.schoolTerm.name }} @@ -24,11 +25,11 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField <template #schoolTerm.field="{ attrs, on }"> <div aria-required="true"> <school-term-field - v-bind="attrs" - v-on="on" - return-object - required - :rules="required" + v-bind="attrs" + v-on="on" + return-object + required + :rules="required" /> </div> </template> @@ -39,11 +40,11 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField <template #dateStart.field="{ attrs, on, item }"> <div aria-required="true"> <date-field - v-bind="attrs" - v-on="on" - :rules="required" - :max="item ? item.dateEnd : undefined" - required + v-bind="attrs" + v-on="on" + :rules="required" + :max="item ? item.dateEnd : undefined" + required ></date-field> </div> </template> @@ -54,11 +55,11 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField <template #dateEnd.field="{ attrs, on, item }"> <div aria-required="true"> <date-field - v-bind="attrs" - v-on="on" - required - :rules="required" - :min="item ? item.dateStart : undefined" + v-bind="attrs" + v-on="on" + required + :rules="required" + :min="item ? item.dateStart : undefined" ></date-field> </div> </template> @@ -100,7 +101,7 @@ export default { { text: this.$t("school_term.title"), value: "schoolTerm", - orderKey: "school_term__date_start" + orderKey: "school_term__date_start", }, { text: this.$t("lesrooster.validity_range.date_start"), @@ -131,19 +132,19 @@ export default { console.log("in getCreateData", item); return { ...item, - schoolTerm: item.schoolTerm?.id - } + schoolTerm: item.schoolTerm?.id, + }; }, getPatchData(items) { console.log("patch items", items); - return items.map(item => ({ + return items.map((item) => ({ id: item.id, name: item.name, dateStart: item.dateStart, dateEnd: item.dateEnd, schoolTerm: item.schoolTerm.id, })); - } + }, }, }; </script> diff --git a/aleksis/apps/lesrooster/frontend/components/ValidityRangeField.vue b/aleksis/apps/lesrooster/frontend/components/ValidityRangeField.vue index 9a20c3af..93cd113c 100644 --- a/aleksis/apps/lesrooster/frontend/components/ValidityRangeField.vue +++ b/aleksis/apps/lesrooster/frontend/components/ValidityRangeField.vue @@ -1,30 +1,31 @@ <script setup> import ForeignKeyField from "aleksis.core/components/generic/forms/ForeignKeyField.vue"; import DateField from "aleksis.core/components/generic/forms/DateField.vue"; -import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField.vue";</script> +import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField.vue"; +</script> <template> <foreign-key-field - v-bind="$attrs" - v-on="$listeners" - :fields="headers" - create-item-i18n-key="lesrooster.validity_range.create_validity_range" - :gql-query="gqlQuery" - :gql-create-mutation="gqlCreateMutation" - :gql-patch-mutation="{}" - :default-item="defaultItem" - :get-create-data="getCreateData" - :get-patch-data="getPatchData" - return-object + v-bind="$attrs" + v-on="$listeners" + :fields="headers" + create-item-i18n-key="lesrooster.validity_range.create_validity_range" + :gql-query="gqlQuery" + :gql-create-mutation="gqlCreateMutation" + :gql-patch-mutation="{}" + :default-item="defaultItem" + :get-create-data="getCreateData" + :get-patch-data="getPatchData" + return-object > <template #schoolTerm.field="{ attrs, on }"> <div aria-required="true"> <school-term-field - v-bind="attrs" - v-on="on" - return-object - :rules="required" - required + v-bind="attrs" + v-on="on" + return-object + :rules="required" + required /> </div> </template> @@ -32,10 +33,10 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField <template #dateStart.field="{ attrs, on, item }"> <div aria-required="true"> <date-field - v-bind="attrs" - v-on="on" - :rules="required" - :max="item ? item.dateEnd : undefined" + v-bind="attrs" + v-on="on" + :rules="required" + :max="item ? item.dateEnd : undefined" ></date-field> </div> </template> @@ -43,11 +44,11 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField <template #dateEnd.field="{ attrs, on, item }"> <div aria-required="true"> <date-field - v-bind="attrs" - v-on="on" - required - :rules="required" - :min="item ? item.dateStart : undefined" + v-bind="attrs" + v-on="on" + required + :rules="required" + :min="item ? item.dateStart : undefined" ></date-field> </div> </template> @@ -55,10 +56,7 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField </template> <script> -import { - validityRanges, - createValidityRange, -} from "./validityRange.graphql"; +import { validityRanges, createValidityRange } from "./validityRange.graphql"; export default { name: "ValidityRangeField", @@ -99,19 +97,19 @@ export default { console.log("in getCreateData", item); return { ...item, - schoolTerm: item.schoolTerm?.id - } + schoolTerm: item.schoolTerm?.id, + }; }, getPatchData(items) { console.log("patch items", items); - return items.map(item => ({ + return items.map((item) => ({ id: item.id, name: item.name, dateStart: item.dateStart, dateEnd: item.dateEnd, schoolTerm: item.schoolTerm.id, })); - } + }, }, }; </script> diff --git a/aleksis/apps/lesrooster/frontend/components/break.graphql b/aleksis/apps/lesrooster/frontend/components/break.graphql index db3234e5..f90c226c 100644 --- a/aleksis/apps/lesrooster/frontend/components/break.graphql +++ b/aleksis/apps/lesrooster/frontend/components/break.graphql @@ -1,64 +1,64 @@ query breakSlots($orderBy: [String], $filters: JSONString) { - items: breakSlots(orderBy: $orderBy, filters: $filters) { - id - name - validityRange { - id - name - } - weekday - period: periodAfter - timeStart - timeEnd - canEdit - canDelete + items: breakSlots(orderBy: $orderBy, filters: $filters) { + id + name + validityRange { + id + name } + weekday + period: periodAfter + timeStart + timeEnd + canEdit + canDelete + } } mutation createBreakSlot($input: CreateBreakInput!) { - createBreakSlot(input: $input) { - item: breakSlot { - id - name - validityRange { - id - name - } - weekday - period: periodAfter - timeStart - timeEnd - canEdit - canDelete - } + createBreakSlot(input: $input) { + item: breakSlot { + id + name + validityRange { + id + name + } + weekday + period: periodAfter + timeStart + timeEnd + canEdit + canDelete } + } } mutation createBreakSlots($input: [BatchCreateBreakInput]!) { - createBreakSlots(input: $input) { - items: breakSlots { - id - model - name - validityRange { - id - name - } - weekday - period: periodAfter - periodAfter - timeStart - timeEnd - canEdit - canDelete - } + createBreakSlots(input: $input) { + items: breakSlots { + id + model + name + validityRange { + id + name + } + weekday + period: periodAfter + periodAfter + timeStart + timeEnd + canEdit + canDelete } + } } mutation deleteBreakSlot($id: ID!) { - deleteBreakSlot(id: $id) { - ok - } + deleteBreakSlot(id: $id) { + ok + } } mutation deleteBreakSlots($ids: [ID]!) { @@ -68,20 +68,20 @@ mutation deleteBreakSlots($ids: [ID]!) { } mutation updateBreakSlots($input: [BatchPatchBreakInput]!) { - batchMutation: updateBreakSlots(input: $input) { - items: breakSlots { - id - name - validityRange { - id - name - } - weekday - period: periodAfter - timeStart - timeEnd - canEdit - canDelete - } + batchMutation: updateBreakSlots(input: $input) { + items: breakSlots { + id + name + validityRange { + id + name + } + weekday + period: periodAfter + timeStart + timeEnd + canEdit + canDelete } + } } diff --git a/aleksis/apps/lesrooster/frontend/components/helper.graphql b/aleksis/apps/lesrooster/frontend/components/helper.graphql index 19316774..5b14b5ed 100644 --- a/aleksis/apps/lesrooster/frontend/components/helper.graphql +++ b/aleksis/apps/lesrooster/frontend/components/helper.graphql @@ -1,57 +1,57 @@ query gqlPersons { - persons { - id - fullName - } + persons { + id + fullName + } } query gqlTeachers { - persons: lesroosterExtendedTeachers { - id - fullName - shortName - lessonQuota - } + persons: lesroosterExtendedTeachers { + id + fullName + shortName + lessonQuota + } } query gqlGroups { - groups { - id - name - shortName - } + groups { + id + name + shortName + } } query gqlClasses { - groups: schoolClasses { - id - name - shortName - } + groups: schoolClasses { + id + name + shortName + } } query gqlClassesByGrade($grade: ID!) { - groups: classesByGrade(grade: $grade) { - id - name - shortName - } + groups: classesByGrade(grade: $grade) { + id + name + shortName + } } query gqlCourses { - courses { - id - name - subject { - id - shortName - name - colourFg - colourBg - } - teachers { - id - fullName - } + courses { + id + name + subject { + id + shortName + name + colourFg + colourBg + } + teachers { + id + fullName } + } } diff --git a/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue b/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue index c95385e1..af7873a7 100644 --- a/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue +++ b/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue @@ -1,39 +1,50 @@ <template> <div id="slot-container"> <v-card class="sidebar"> - <v-navigation-drawer - floating - permanent - > + <v-navigation-drawer floating permanent> <v-list dense rounded> <validity-range-field - solo - rounded - hide-details - v-model="internalValidityRange" - :loading="$apollo.queries.currentValidityRange.loading" + solo + rounded + hide-details + v-model="internalValidityRange" + :loading="$apollo.queries.currentValidityRange.loading" /> <slot-creator - :query="$apollo.queries.items" - :validity-range="internalValidityRange.id" - v-if="internalValidityRange" - :breaks="createBreaks" + :query="$apollo.queries.items" + :validity-range="internalValidityRange.id" + v-if="internalValidityRange" + :breaks="createBreaks" > <template #activator="{ on, attrs }"> - <v-list-item link v-bind="attrs" v-on="on" @click="createBreaks = false"> + <v-list-item + link + v-bind="attrs" + v-on="on" + @click="createBreaks = false" + > <v-list-item-icon> <v-icon>$plus</v-icon> </v-list-item-icon> <v-list-item-content> - <v-list-item-title>{{ $t("lesrooster.slot.create_items") }}</v-list-item-title> + <v-list-item-title>{{ + $t("lesrooster.slot.create_items") + }}</v-list-item-title> </v-list-item-content> </v-list-item> - <v-list-item link v-bind="attrs" v-on="on" @click="createBreaks = true"> + <v-list-item + link + v-bind="attrs" + v-on="on" + @click="createBreaks = true" + > <v-list-item-icon> <v-icon>$plus</v-icon> </v-list-item-icon> <v-list-item-content> - <v-list-item-title>{{ $t("lesrooster.break.create_items") }}</v-list-item-title> + <v-list-item-title>{{ + $t("lesrooster.break.create_items") + }}</v-list-item-title> </v-list-item-content> </v-list-item> </template> @@ -43,24 +54,26 @@ </v-card> <v-hover - v-for="weekday in weekdays" - :style="{ - gridColumn: weekday, - }" - v-slot="{ hover }" + v-for="weekday in weekdays" + :style="{ + gridColumn: weekday, + }" + v-slot="{ hover }" > <v-card :loading="$apollo.queries.items.loading"> - <v-card-title class="d-flex flex-wrap justify-space-between align-center fill-height"> + <v-card-title + class="d-flex flex-wrap justify-space-between align-center fill-height" + > <span class="min-height">{{ $t("weekdays." + weekday) }}</span> <v-tooltip bottom> <template #activator="{ on, attrs }"> <v-btn - @click="deleteSlotsOfDay(weekday)" - icon - v-bind="attrs" - v-on="on" - v-show="hover" + @click="deleteSlotsOfDay(weekday)" + icon + v-bind="attrs" + v-on="on" + v-show="hover" > <v-icon>$deleteContent</v-icon> </v-btn> @@ -73,11 +86,11 @@ <v-tooltip bottom> <template #activator="{ on: tooltip }"> <v-btn - icon - v-bind="attrs" - v-on="{ ...tooltip, ...menu }" - :loading="loading[weekday]" - v-show="hover" + icon + v-bind="attrs" + v-on="{ ...tooltip, ...menu }" + :loading="loading[weekday]" + v-show="hover" > <v-icon>mdi-application-export</v-icon> </v-btn> @@ -87,41 +100,44 @@ </template> <v-list> <v-list-item - v-for="(item, index) in weekdays.filter(day => day !== weekday)" - :key="index" - link + v-for="(item, index) in weekdays.filter( + (day) => day !== weekday + )" + :key="index" + link > - <v-list-item-title @click="copyTo(weekday, item)">{{ $t("weekdays." + item) }}</v-list-item-title> + <v-list-item-title @click="copyTo(weekday, item)">{{ + $t("weekdays." + item) + }}</v-list-item-title> </v-list-item> </v-list> </v-menu> - <v-btn - v-if="canAddDay(left(weekday))" - v-show="hover" - color="secondary" - fab - dark - small - absolute - left - style="left: calc(-20px - 0.5rem)" - @click="add(left(weekday))" + v-if="canAddDay(left(weekday))" + v-show="hover" + color="secondary" + fab + dark + small + absolute + left + style="left: calc(-20px - 0.5rem)" + @click="add(left(weekday))" > <v-icon>mdi-table-column-plus-before</v-icon> </v-btn> <v-btn - v-if="canAddDay(right(weekday))" - v-show="hover" - color="secondary" - fab - dark - small - absolute - right - style="right: calc(-20px - 0.5rem)" - @click="add(right(weekday))" + v-if="canAddDay(right(weekday))" + v-show="hover" + color="secondary" + fab + dark + small + absolute + right + style="right: calc(-20px - 0.5rem)" + @click="add(right(weekday))" > <v-icon>mdi-table-column-plus-after</v-icon> </v-btn> @@ -129,28 +145,27 @@ </v-card> </v-hover> - <template - v-for="slot in slots" - > + <template v-for="slot in slots"> <v-menu offset-y> <template #activator="{ on, attrs }"> <slot-card - :item="slot" - :disabled="$apollo.queries.items.loading" - @click:delete="deleteSingularSlot" - @click:copy="on.click" - v-bind="attrs" + :item="slot" + :disabled="$apollo.queries.items.loading" + @click:delete="deleteSingularSlot" + @click:copy="on.click" + v-bind="attrs" /> </template> <v-list> <v-list-item - v-for="(item, index) in weekdays.filter(day => day !== slot.weekday)" - :key="index" - link + v-for="(item, index) in weekdays.filter( + (day) => day !== slot.weekday + )" + :key="index" + link > - <v-list-item-title @click="copySingularSlotTodDay(slot, item)">{{ - $t("weekdays." + item) - }} + <v-list-item-title @click="copySingularSlotTodDay(slot, item)" + >{{ $t("weekdays." + item) }} </v-list-item-title> </v-list-item> </v-list> @@ -158,24 +173,33 @@ </template> <delete-dialog - :gql-mutation="deleteMutation" - :gql-query="$apollo.queries.items" - v-model="deleteDialog" - :item="itemToDelete" + :gql-mutation="deleteMutation" + :gql-query="$apollo.queries.items" + v-model="deleteDialog" + :item="itemToDelete" > <template #body> - {{ $t("lesrooster." + itemToDelete.model.toLowerCase() + ".repr", itemToDelete) }} + {{ + $t( + "lesrooster." + itemToDelete.model.toLowerCase() + ".repr", + itemToDelete + ) + }} </template> </delete-dialog> <delete-multiple-dialog - :gql-mutation="deleteMultipleMutation" - :gql-query="$apollo.queries.items" - :items="itemsToDelete" - v-model="deleteMultipleDialog" + :gql-mutation="deleteMultipleMutation" + :gql-query="$apollo.queries.items" + :items="itemsToDelete" + v-model="deleteMultipleDialog" > <template #title> - {{ $t('lesrooster.slot.confirm_delete_multiple_slots', {day: $t("weekdays." + weekdays[0])}) }} + {{ + $t("lesrooster.slot.confirm_delete_multiple_slots", { + day: $t("weekdays." + weekdays[0]), + }) + }} </template> <template #body> @@ -190,7 +214,7 @@ </template> <script> -import {createBreakSlot, deleteBreakSlots} from "../break.graphql"; +import { createBreakSlot, deleteBreakSlots } from "../break.graphql"; import { carryOverSlots, slots, @@ -199,7 +223,7 @@ import { deleteSlots, updateSlots, } from "../slot.graphql"; -import {currentValidityRange} from "../validityRange.graphql"; +import { currentValidityRange } from "../validityRange.graphql"; import ValidityRangeField from "../ValidityRangeField.vue"; import DeleteDialog from "aleksis.core/components/generic/dialogs/DeleteDialog.vue"; import DeleteMultipleDialog from "aleksis.core/components/generic/dialogs/DeleteMultipleDialog.vue"; @@ -209,30 +233,39 @@ import SlotCreator from "./SlotCreator.vue"; export default { name: "LessonRaster", - components: {SlotCreator, DeleteDialog, DeleteMultipleDialog, SlotCard, SecondaryActionButton, ValidityRangeField}, + components: { + SlotCreator, + DeleteDialog, + DeleteMultipleDialog, + SlotCard, + SecondaryActionButton, + ValidityRangeField, + }, apollo: { items: { query: slots, variables() { return { filters: JSON.stringify({ - "validity_range": this.internalValidityRange.id - }) - } + validity_range: this.internalValidityRange.id, + }), + }; }, result(data) { - this.weekdays = Array.from(new Set(data.data.items.map(slot => slot.weekday))); + this.weekdays = Array.from( + new Set(data.data.items.map((slot) => slot.weekday)) + ); }, skip() { return this.internalValidityRange === null; - } + }, }, currentValidityRange: { query: currentValidityRange, result(data) { this.internalValidityRange = data.data.currentValidityRange; - } - } + }, + }, }, data() { return { @@ -247,17 +280,17 @@ export default { itemToDelete: null, itemsToDelete: [], createBreaks: false, - } + }; }, computed: { slots() { return this.items; }, columns() { - return "[side] 256px " + this.weekdays.map( - day => `[${day}] 1fr` - ).join(" "); - } + return ( + "[side] 256px " + this.weekdays.map((day) => `[${day}] 1fr`).join(" ") + ); + }, }, methods: { intDay(weekday) { @@ -272,24 +305,28 @@ export default { }, add(weekday) { if (!this.weekdays.includes(weekday)) { - this.weekdays.push(weekday) + this.weekdays.push(weekday); this.weekdays.sort(); } }, right(weekday) { - return weekday === "A_6" ? null : weekday.replace(/\d+$/, (match) => parseInt(match) + 1); + return weekday === "A_6" + ? null + : weekday.replace(/\d+$/, (match) => parseInt(match) + 1); }, left(weekday) { - return weekday === "A_0" ? null : weekday.replace(/\d+$/, (match) => parseInt(match) - 1); + return weekday === "A_0" + ? null + : weekday.replace(/\d+$/, (match) => parseInt(match) - 1); }, async copyTo(src, dest) { this.loading[dest] = true; const slotsToDelete = this.items - .filter(slot => slot.weekday === dest && slot.model === "Slot") - .map(slot => slot.id); + .filter((slot) => slot.weekday === dest && slot.model === "Slot") + .map((slot) => slot.id); const breaksToDelete = this.items - .filter(slot => slot.weekday === dest && slot.model === "Break") - .map(slot => slot.id); + .filter((slot) => slot.weekday === dest && slot.model === "Break") + .map((slot) => slot.id); // As there is an error when deleting breaks and normal slots in one action, we delete them separately @@ -302,11 +339,20 @@ export default { fromDay: this.intDay(src), toDay: this.intDay(dest), }, - update(store, {data: {carryOverSlots: {result}}}) { + update( + store, + { + data: { + carryOverSlots: { result }, + }, + } + ) { let query = { ...that.$apollo.queries.items.options, - variables: JSON.parse(that.$apollo.queries.items.previousVariablesJson) - } + variables: JSON.parse( + that.$apollo.queries.items.previousVariablesJson + ), + }; // Read the data from cache for query const storedData = store.readQuery(query); @@ -316,16 +362,16 @@ export default { } storedData.items = [ - ...storedData.items.filter(item => item.weekday !== dest), + ...storedData.items.filter((item) => item.weekday !== dest), ...result, - ] + ]; // Write data back to the cache - store.writeQuery({...query, data: storedData}); - } - }) + store.writeQuery({ ...query, data: storedData }); + }, + }); - this.weekdays = this.weekdays.sort((a, b) => a[2] - b[2]) + this.weekdays = this.weekdays.sort((a, b) => a[2] - b[2]); this.loading[dest] = false; }, async copySingularSlotTodDay(slot, day) { @@ -338,7 +384,7 @@ export default { toDay: this.intDay(day), only: [slot.id], }, - }) + }); // FIXME: Optimistic response; add to store? await this.$apollo.queries.items.refetch(); this.loading[day] = false; @@ -348,11 +394,13 @@ export default { this.deleteDialog = true; }, deleteSlotsOfDay(weekday) { - this.itemsToDelete = this.items.filter(slot => slot.weekday === weekday) + this.itemsToDelete = this.items.filter( + (slot) => slot.weekday === weekday + ); this.deleteMultipleDialog = true; - } + }, }, -} +}; </script> <style scoped> @@ -374,4 +422,4 @@ export default { position: fixed; z-index: 1; } -</style> \ No newline at end of file +</style> diff --git a/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCard.vue b/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCard.vue index c32da150..bab13e9c 100644 --- a/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCard.vue +++ b/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCard.vue @@ -1,5 +1,5 @@ <script> -import {defineComponent} from 'vue' +import { defineComponent } from "vue"; export default defineComponent({ name: "SlotCard", @@ -25,18 +25,19 @@ export default defineComponent({ }, handleCopy(event) { this.$emit("click:copy", event, this.item); - } + }, }, -}) +}); </script> <template> <v-card - :style="{ - gridColumn: item.weekday, - gridRow: item.model === 'Slot' ? (item.period * 2) + 1 : (item.periodAfter) * 2, - }" - :disabled="disabled" + :style="{ + gridColumn: item.weekday, + gridRow: + item.model === 'Slot' ? item.period * 2 + 1 : item.periodAfter * 2, + }" + :disabled="disabled" > <v-hover v-slot="{ hover }"> <v-card-text class="d-flex align-center"> @@ -46,19 +47,26 @@ export default defineComponent({ </v-col> <v-col cols="6"> - <div class="time">{{ $d(new Date("1970-01-01T" + item.timeStart), "shortTime") }}</div> - <div class="time">{{ $d(new Date("1970-01-01T" + item.timeEnd), "shortTime") }}</div> + <div class="time"> + {{ $d(new Date("1970-01-01T" + item.timeStart), "shortTime") }} + </div> + <div class="time"> + {{ $d(new Date("1970-01-01T" + item.timeEnd), "shortTime") }} + </div> </v-col> - <v-col cols="2" class="d-flex flex-column align-center pa-0 my-n1 hover-box"> + <v-col + cols="2" + class="d-flex flex-column align-center pa-0 my-n1 hover-box" + > <v-tooltip left> <template #activator="{ on, attrs }"> <v-btn - icon - v-bind="attrs" - v-on="on" - @click="handleDelete" - v-show="hover" + icon + v-bind="attrs" + v-on="on" + @click="handleDelete" + v-show="hover" > <v-icon>$deleteContent</v-icon> </v-btn> @@ -69,11 +77,11 @@ export default defineComponent({ <v-tooltip left> <template #activator="{ on, attrs }"> <v-btn - icon - v-bind="attrs" - v-on="on" - @click="handleCopy" - v-show="hover" + icon + v-bind="attrs" + v-on="on" + @click="handleCopy" + v-show="hover" > <v-icon>mdi-application-export</v-icon> </v-btn> @@ -92,7 +100,7 @@ export default defineComponent({ } .hover-box { - padding-inline-end: .5em !important; - min-width: calc(36px + .5em); + padding-inline-end: 0.5em !important; + min-width: calc(36px + 0.5em); } -</style> \ No newline at end of file +</style> diff --git a/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCreator.vue b/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCreator.vue index 66923163..927d40b0 100644 --- a/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCreator.vue +++ b/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCreator.vue @@ -1,7 +1,7 @@ <script> -import {defineComponent} from 'vue'; -import {createSlots} from "../slot.graphql"; -import {createBreakSlots} from "../break.graphql"; +import { defineComponent } from "vue"; +import { createSlots } from "../slot.graphql"; +import { createBreakSlots } from "../break.graphql"; import CancelButton from "aleksis.core/components/generic/buttons/CancelButton.vue"; import CreateButton from "aleksis.core/components/generic/buttons/CreateButton.vue"; import MobileFullscreenDialog from "aleksis.core/components/generic/dialogs/MobileFullscreenDialog.vue"; @@ -11,7 +11,14 @@ import WeekDayField from "aleksis.core/components/generic/forms/WeekDayField.vue export default defineComponent({ name: "SlotCreator", - components: {CreateButton, CancelButton, PositiveSmallIntegerField, WeekDayField, MobileFullscreenDialog, TimeField}, + components: { + CreateButton, + CancelButton, + PositiveSmallIntegerField, + WeekDayField, + MobileFullscreenDialog, + TimeField, + }, data() { return { dialog: false, @@ -21,10 +28,8 @@ export default defineComponent({ timeStart: "8:00", timeEnd: "9:00", }, - required: [ - value => !!value || this.$t("forms.errors.required"), - ] - } + required: [(value) => !!value || this.$t("forms.errors.required")], + }; }, props: { validityRange: { @@ -39,85 +44,82 @@ export default defineComponent({ query: { type: Object, required: true, - } + }, }, methods: { save() { this.loading = true; - this.$apollo.mutate({ - mutation: this.breaks ? createBreakSlots : createSlots, - variables: { - input: this.slots.weekdays.map( - weekday => ({ - name: "", - validityRange: this.validityRange, - period: this.breaks ? undefined : this.slots.period, - periodAfter: this.breaks ? this.slots.period : undefined, - weekday: parseInt(weekday[2]), - timeStart: this.slots.timeStart, - timeEnd: this.slots.timeEnd, - }) - ), - }, - update: (store, data) => { - let mutationName = this.breaks ? "createBreakSlots" : "createSlots" - this.$emit( - "update", - store, - data.data[mutationName].items - ); + this.$apollo + .mutate({ + mutation: this.breaks ? createBreakSlots : createSlots, + variables: { + input: this.slots.weekdays.map((weekday) => ({ + name: "", + validityRange: this.validityRange, + period: this.breaks ? undefined : this.slots.period, + periodAfter: this.breaks ? this.slots.period : undefined, + weekday: parseInt(weekday[2]), + timeStart: this.slots.timeStart, + timeEnd: this.slots.timeEnd, + })), + }, + update: (store, data) => { + let mutationName = this.breaks ? "createBreakSlots" : "createSlots"; + this.$emit("update", store, data.data[mutationName].items); - let query = { - ...this.query.options, - variables: JSON.parse(this.query.previousVariablesJson) - } - // Read the data from cache for query - const storedData = store.readQuery(query); + let query = { + ...this.query.options, + variables: JSON.parse(this.query.previousVariablesJson), + }; + // Read the data from cache for query + const storedData = store.readQuery(query); - if (!storedData) { - // There are no data in the cache yet - return; - } + if (!storedData) { + // There are no data in the cache yet + return; + } - storedData.items = [ - ...storedData.items, - ...data.data[mutationName].items, - ] + storedData.items = [ + ...storedData.items, + ...data.data[mutationName].items, + ]; - // Write data back to the cache - store.writeQuery({...query, data: storedData}); - }, - }) - .then((data) => { - this.$emit("save", data); + // Write data back to the cache + store.writeQuery({ ...query, data: storedData }); + }, + }) + .then((data) => { + this.$emit("save", data); - this.handleSuccess(); - }) - .catch((error) => { - console.error(error); - this.$emit("error", error); - }) - .finally(() => { - this.loading = false; - this.dialog = false; - }); + this.handleSuccess(); + }) + .catch((error) => { + console.error(error); + this.$emit("error", error); + }) + .finally(() => { + this.loading = false; + this.dialog = false; + }); }, handleSuccess() { this.$root.snackbarItems.push({ id: crypto.randomUUID(), timeout: 5000, - messageKey: `lesrooster.${this.breaks ? "break" : "slot"}.create_items_success`, + messageKey: `lesrooster.${ + this.breaks ? "break" : "slot" + }.create_items_success`, color: "success", }); }, }, -}) +}); </script> <template> <mobile-fullscreen-dialog v-model="dialog"> <template #activator="{ on, attrs }"> - <slot name="activator" v-bind="{ on, attrs }"/> + <slot name="activator" v-bind="{ on, attrs }" /> </template> <template #title> @@ -127,19 +129,19 @@ export default defineComponent({ <template #content> <div aria-required="true"> <positive-small-integer-field - v-model="slots.period" - :label="$t('lesrooster.slot.period')" - :rules="required" + v-model="slots.period" + :label="$t('lesrooster.slot.period')" + :rules="required" /> </div> <div aria-required="true"> <week-day-field - v-model="slots.weekdays" - multiple - chips - :label="$t('lesrooster.slot.weekdays')" - :rules="required" + v-model="slots.weekdays" + multiple + chips + :label="$t('lesrooster.slot.weekdays')" + :rules="required" /> </div> @@ -147,9 +149,9 @@ export default defineComponent({ <v-col> <div aria-required="true"> <time-field - v-model="slots.timeStart" - :label="$t('lesrooster.slot.time_start')" - :rules="required" + v-model="slots.timeStart" + :label="$t('lesrooster.slot.time_start')" + :rules="required" /> </div> </v-col> @@ -157,9 +159,9 @@ export default defineComponent({ <v-col> <div aria-required="true"> <time-field - v-model="slots.timeEnd" - :label="$t('lesrooster.slot.time_end')" - :rules="required" + v-model="slots.timeEnd" + :label="$t('lesrooster.slot.time_end')" + :rules="required" /> </div> </v-col> @@ -167,12 +169,10 @@ export default defineComponent({ </template> <template #actions> - <cancel-button @click="dialog = false"/> - <create-button @click="save"/> + <cancel-button @click="dialog = false" /> + <create-button @click="save" /> </template> </mobile-fullscreen-dialog> </template> -<style scoped> - -</style> \ No newline at end of file +<style scoped></style> diff --git a/aleksis/apps/lesrooster/frontend/components/slot.graphql b/aleksis/apps/lesrooster/frontend/components/slot.graphql index 7bd0fdc5..a2b9636c 100644 --- a/aleksis/apps/lesrooster/frontend/components/slot.graphql +++ b/aleksis/apps/lesrooster/frontend/components/slot.graphql @@ -1,111 +1,121 @@ query slots($orderBy: [String], $filters: JSONString) { - items: slots(orderBy: $orderBy, filters: $filters) { - id - model - name - validityRange { - id - name - } - weekday - period - periodAfter - timeStart - timeEnd - canEdit - canDelete + items: slots(orderBy: $orderBy, filters: $filters) { + id + model + name + validityRange { + id + name } + weekday + period + periodAfter + timeStart + timeEnd + canEdit + canDelete + } } mutation createSlot($input: CreateSlotInput!) { - createSlot(input: $input) { - item: slot { - id - name - validityRange { - id - name - } - weekday - period - timeStart - timeEnd - canEdit - canDelete - } + createSlot(input: $input) { + item: slot { + id + name + validityRange { + id + name + } + weekday + period + timeStart + timeEnd + canEdit + canDelete } + } } mutation createSlots($input: [BatchCreateSlotInput]!) { - createSlots(input: $input) { - items: slots { - id - model - name - validityRange { - id - name - } - weekday - period - periodAfter - timeStart - timeEnd - canEdit - canDelete - } + createSlots(input: $input) { + items: slots { + id + model + name + validityRange { + id + name + } + weekday + period + periodAfter + timeStart + timeEnd + canEdit + canDelete } + } } mutation deleteSlot($id: ID!) { - deleteSlot(id: $id) { - ok - } + deleteSlot(id: $id) { + ok + } } mutation deleteSlots($ids: [ID]!) { - deleteSlots(ids: $ids) { - deletionCount - } + deleteSlots(ids: $ids) { + deletionCount + } } mutation updateSlots($input: [BatchPatchSlotInput]!) { - batchMutation: updateSlots(input: $input) { - items: slots { - id - name - validityRange { - id - name - } - weekday - period - timeStart - timeEnd - canEdit - canDelete - } + batchMutation: updateSlots(input: $input) { + items: slots { + id + name + validityRange { + id + name + } + weekday + period + timeStart + timeEnd + canEdit + canDelete } + } } -mutation carryOverSlots($validityRange: ID!, $fromDay: Int!, $toDay: Int!, $only: [ID]) { - carryOverSlots(validityRange: $validityRange, fromDay: $fromDay, toDay: $toDay, only: $only) { - deleted - result { - id - model - name - validityRange { - id - name - } - weekday - period - periodAfter - timeStart - timeEnd - canEdit - canDelete - } +mutation carryOverSlots( + $validityRange: ID! + $fromDay: Int! + $toDay: Int! + $only: [ID] +) { + carryOverSlots( + validityRange: $validityRange + fromDay: $fromDay + toDay: $toDay + only: $only + ) { + deleted + result { + id + model + name + validityRange { + id + name + } + weekday + period + periodAfter + timeStart + timeEnd + canEdit + canDelete } + } } diff --git a/aleksis/apps/lesrooster/frontend/components/timeboundCourseConfig.graphql b/aleksis/apps/lesrooster/frontend/components/timeboundCourseConfig.graphql index 07477654..68cae81a 100644 --- a/aleksis/apps/lesrooster/frontend/components/timeboundCourseConfig.graphql +++ b/aleksis/apps/lesrooster/frontend/components/timeboundCourseConfig.graphql @@ -55,7 +55,9 @@ query timeboundCourseConfigs($orderBy: [String], $filters: JSONString) { } } -mutation createTimeboundCourseConfig($input: createTimeboundCourseConfigInput!) { +mutation createTimeboundCourseConfig( + $input: createTimeboundCourseConfigInput! +) { createTimeboundCourseConfig(input: $input) { item: timeboundCourseConfigs { ...timeboundCourseConfigFields @@ -69,7 +71,9 @@ mutation createTimeboundCourseConfig($input: createTimeboundCourseConfigInput!) } } -mutation batchCreateTimeboundCourseConfig($input: [BatchCreateTimeboundCourseConfigInput]!) { +mutation batchCreateTimeboundCourseConfig( + $input: [BatchCreateTimeboundCourseConfigInput]! +) { batchCreateTimeboundCourseConfig(input: $input) { item: timeboundCourseConfigs { ...timeboundCourseConfigFields @@ -89,7 +93,9 @@ mutation deleteTimeboundCourseConfig($id: ID!) { } } -mutation updateTimeboundCourseConfigs($input: [BatchPatchTimeboundCourseConfigInput]!) { +mutation updateTimeboundCourseConfigs( + $input: [BatchPatchTimeboundCourseConfigInput]! +) { batchMutation: updateTimeboundCourseConfigs(input: $input) { items: timeboundCourseConfigs { ...timeboundCourseConfigFields @@ -104,7 +110,11 @@ mutation updateTimeboundCourseConfigs($input: [BatchPatchTimeboundCourseConfigIn } query subjects($orderBy: [String], $filters: JSONString, $courses: [ID]) { - subjects: lesroosterExtendedSubjects(orderBy: $orderBy, filters: $filters, courses: $courses) { + subjects: lesroosterExtendedSubjects( + orderBy: $orderBy + filters: $filters + courses: $courses + ) { ...subjectFields courses { ...courseFields diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/LessonCard.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/LessonCard.vue index b09512cc..f9569af8 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/LessonCard.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/LessonCard.vue @@ -1,5 +1,5 @@ <script> -import {defineComponent} from 'vue' +import { defineComponent } from "vue"; export default defineComponent({ name: "LessonCard", @@ -7,11 +7,11 @@ export default defineComponent({ lesson: { type: Object, required: true, - } + }, }, computed: { subject() { - return this.lesson.subject || this.lesson.course.subject || {name: ""}; + return this.lesson.subject || this.lesson.course.subject || { name: "" }; }, teachers() { return this.lesson.teachers || this.lesson.course.teachers || []; @@ -20,7 +20,7 @@ export default defineComponent({ return this.lesson.groups || this.lesson.course.groups || []; }, }, -}) +}); </script> <template> @@ -35,6 +35,4 @@ export default defineComponent({ </v-card> </template> -<style scoped> - -</style> \ No newline at end of file +<style scoped></style> diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue index edf5219b..ba167266 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue @@ -1,8 +1,8 @@ <script> -import {defineComponent} from 'vue' -import {group} from "./timetableManagement.graphql"; -import {currentValidityRange} from "../validityRange.graphql"; -import {slots} from "../slot.graphql"; +import { defineComponent } from "vue"; +import { group } from "./timetableManagement.graphql"; +import { currentValidityRange } from "../validityRange.graphql"; +import { slots } from "../slot.graphql"; import SecondaryActionButton from "aleksis.core/components/generic/buttons/SecondaryActionButton.vue"; import SaveButton from "aleksis.core/components/generic/buttons/SaveButton.vue"; import ValidityRangeField from "../ValidityRangeField.vue"; @@ -10,13 +10,13 @@ import validityRange from "../ValidityRange.vue"; export default defineComponent({ name: "TimetableManagement", - components: {SecondaryActionButton, SaveButton, ValidityRangeField}, + components: { SecondaryActionButton, SaveButton, ValidityRangeField }, data() { return { weekdays: [], periods: [], internalValidityRange: null, - } + }; }, apollo: { group: { @@ -26,65 +26,79 @@ export default defineComponent({ id: this.$route.params.id, }; }, - update: data => data.groupById, - result({data: {groupById}}) { - this.$setToolBarTitle(this.$t("lesrooster.timetable_management.for_group", {group: groupById.name})) - } + update: (data) => data.groupById, + result({ data: { groupById } }) { + this.$setToolBarTitle( + this.$t("lesrooster.timetable_management.for_group", { + group: groupById.name, + }) + ); + }, }, slots: { query: slots, variables() { return { filters: JSON.stringify({ - "validity_range": this.internalValidityRange.id - }) - } + validity_range: this.internalValidityRange.id, + }), + }; }, skip() { return this.internalValidityRange === null; }, - update: data => data.items, - result({data: {items}}) { - this.weekdays = Array.from(new Set(items.filter(slot => slot.model === "Slot").map(slot => slot.weekday))); - this.periods = Array.from(new Set(items.filter(slot => slot.model === "Slot").map(slot => slot.period))); + update: (data) => data.items, + result({ data: { items } }) { + this.weekdays = Array.from( + new Set( + items + .filter((slot) => slot.model === "Slot") + .map((slot) => slot.weekday) + ) + ); + this.periods = Array.from( + new Set( + items + .filter((slot) => slot.model === "Slot") + .map((slot) => slot.period) + ) + ); }, }, currentValidityRange: { query: currentValidityRange, result(data) { this.internalValidityRange = data.data.currentValidityRange; - } - } + }, + }, }, computed: { validityRange() { - return validityRange + return validityRange; }, lessons() { - return this.slots ? - this.slots - .filter(slot => slot.model === "Slot") - .map( - slot => ( - { - x: this.weekdays.indexOf(slot.weekday) + 1, - y: this.periods.indexOf(slot.period) + 1, - w: 1, - h: 1, - key: slot.id, - data: {text: "Hello world 1"}, - } - ) - ) - : []; + return this.slots + ? this.slots + .filter((slot) => slot.model === "Slot") + .map((slot) => ({ + x: this.weekdays.indexOf(slot.weekday) + 1, + y: this.periods.indexOf(slot.period) + 1, + w: 1, + h: 1, + key: slot.id, + data: { text: "Hello world 1" }, + })) + : []; }, gridLoading() { - return this.$apollo.queries.slots.loading - || this.$apollo.queries.currentValidityRange.loading - || this.$apollo.queries.group.loading - } + return ( + this.$apollo.queries.slots.loading || + this.$apollo.queries.currentValidityRange.loading || + this.$apollo.queries.group.loading + ); + }, }, -}) +}); </script> <template> @@ -92,37 +106,41 @@ export default defineComponent({ <v-row> <v-col cols="12" lg="8"> <div class="d-flex justify-space-between flex-wrap align-center"> - <secondary-action-button i18n-key="IDK, ggf back??"/> + <secondary-action-button i18n-key="IDK, ggf back??" /> - <v-spacer/> + <v-spacer /> <validity-range-field - solo - rounded - hide-details - v-model="internalValidityRange" - :loading="$apollo.queries.currentValidityRange.loading" + solo + rounded + hide-details + v-model="internalValidityRange" + :loading="$apollo.queries.currentValidityRange.loading" /> </div> </v-col> - <v-col cols="12" lg="4" class="d-flex justify-space-between flex-wrap align-center"> - <save-button/> - <secondary-action-button i18n-key="actions.copy_last_configuration"/> + <v-col + cols="12" + lg="4" + class="d-flex justify-space-between flex-wrap align-center" + > + <save-button /> + <secondary-action-button i18n-key="actions.copy_last_configuration" /> </v-col> <v-col cols="12" lg="8"> <drag-grid - :cols="weekdays.length" - :rows="periods.length" - :value="lessons" - :loading="gridLoading" + :cols="weekdays.length" + :rows="periods.length" + :value="lessons" + :loading="gridLoading" > <template #item="item"> <v-card>{{ item.data.text }}</v-card> </template> <template #loader> - <v-skeleton-loader type="sentences"/> + <v-skeleton-loader type="sentences" /> </template> </drag-grid> </v-col> @@ -131,22 +149,15 @@ export default defineComponent({ <v-card> <v-card-text> <v-card-title>Courses</v-card-title> - <v-autocomplete search solo rounded hide-details/> + <v-autocomplete search solo rounded hide-details /> </v-card-text> </v-card> </v-col> - <v-col cols="12" md="6"> - Timetable Teacher - </v-col> - <v-col cols="12" md="6"> - Timetable Room - </v-col> + <v-col cols="12" md="6"> Timetable Teacher </v-col> + <v-col cols="12" md="6"> Timetable Room </v-col> </v-row> - </div> </template> -<style scoped> - -</style> \ No newline at end of file +<style scoped></style> diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql b/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql index 12cc6a94..f65e24b8 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql @@ -1,6 +1,6 @@ query group($id: ID!) { - groupById(id: $id) { - id - name - } + groupById(id: $id) { + id + name + } } diff --git a/aleksis/apps/lesrooster/frontend/index.js b/aleksis/apps/lesrooster/frontend/index.js index 1cb2f891..eff04569 100644 --- a/aleksis/apps/lesrooster/frontend/index.js +++ b/aleksis/apps/lesrooster/frontend/index.js @@ -1,96 +1,96 @@ import { hasPersonValidator } from "aleksis.core/routeValidators"; export default { - component: () => import("aleksis.core/components/Parent.vue"), - meta: { + component: () => import("aleksis.core/components/Parent.vue"), + meta: { + inMenu: true, + titleKey: "lesrooster.menu_title", + icon: "mdi-timetable", + validators: [hasPersonValidator], + permission: "lesrooster.view_lesrooster_menu_rule", + }, + children: [ + { + path: "validity-ranges/", + component: () => import("./components/ValidityRange.vue"), + name: "lesrooster.validity_ranges", + meta: { inMenu: true, - titleKey: "lesrooster.menu_title", + titleKey: "lesrooster.validity_range.menu_title", + icon: "mdi-calendar-expand-horizontal-outline", + permission: "lesrooster.view_validity_ranges_rule", + }, + }, + { + path: "raster/", + component: () => import("./components/lesson_raster/LessonRaster.vue"), + name: "lesrooster.lesson_raster", + meta: { + inMenu: true, + titleKey: "lesrooster.lesson_raster.menu_title", + toolbarTitle: "lesrooster.lesson_raster.menu_title", + icon: "mdi-grid-large", + permission: "lesrooster.view_lesson_raster_rule", + }, + }, + { + path: "timetable/:id(\\d+)/", + component: () => + import("./components/timetable_management/TimetableManagement.vue"), + name: "lesrooster.timetable_management", + props: true, + meta: { + inMenu: true, + titleKey: "lesrooster.timetable_management.menu_title", + toolbarTitle: "lesrooster.timetable_management.menu_title", + icon: "mdi-magnet", + permission: "lesrooster.view_timetable_creation_rule", + }, + }, + { + path: "slots/", + component: () => import("./components/LesroosterSlot.vue"), + name: "lesrooster.slots", + meta: { + inMenu: true, + titleKey: "lesrooster.slot.menu_title", + icon: "mdi-border-none-variant", + permission: "lesrooster.view_slots_rule", + }, + }, + { + path: "breaks/", + component: () => import("./components/Break.vue"), + name: "lesrooster.breaks", + meta: { + inMenu: true, + titleKey: "lesrooster.break.menu_title", + icon: "mdi-timer-sand-paused", + permission: "lesrooster.view_breaks_rule", + }, + }, + { + path: "timebound_course_configs/", + component: () => + import("./components/TimeboundCourseConfigCRUDTable.vue"), + name: "lesrooster.timeboundCourseConfigs", + meta: { + inMenu: true, + titleKey: "lesrooster.timebound_course_config.crud_table_menu_title", icon: "mdi-timetable", - validators: [ - hasPersonValidator - ], - permission: "lesrooster.view_lesrooster_menu_rule", + permission: "lesrooster.view_timebound_course_configs_rule", + }, + }, + { + path: "timebound_course_configs/plan_courses/", + component: () => import("./components/TimeboundCourseConfigRaster.vue"), + name: "lesrooster.planCourses", + meta: { + inMenu: true, + titleKey: "lesrooster.timebound_course_config.raster_menu_title", + icon: "mdi-clock-edit-outline", + permission: "lesrooster.view_timebound_course_configs_rule", + }, }, - children: [ - { - path: "validity-ranges/", - component: () => import("./components/ValidityRange.vue"), - name: "lesrooster.validity_ranges", - meta: { - inMenu: true, - titleKey: "lesrooster.validity_range.menu_title", - icon: "mdi-calendar-expand-horizontal-outline", - permission: "lesrooster.view_validity_ranges_rule", - }, - }, - { - path: "raster/", - component: () => import("./components/lesson_raster/LessonRaster.vue"), - name: "lesrooster.lesson_raster", - meta: { - inMenu: true, - titleKey: "lesrooster.lesson_raster.menu_title", - toolbarTitle: "lesrooster.lesson_raster.menu_title", - icon: "mdi-grid-large", - permission: "lesrooster.view_lesson_raster_rule", - } - }, - { - path: "timetable/:id(\\d+)/", - component: () => import("./components/timetable_management/TimetableManagement.vue"), - name: "lesrooster.timetable_management", - props: true, - meta: { - inMenu: true, - titleKey: "lesrooster.timetable_management.menu_title", - toolbarTitle: "lesrooster.timetable_management.menu_title", - icon: "mdi-magnet", - permission: "lesrooster.view_timetable_creation_rule", - } - }, - { - path: "slots/", - component: () => import("./components/LesroosterSlot.vue"), - name: "lesrooster.slots", - meta: { - inMenu: true, - titleKey: "lesrooster.slot.menu_title", - icon: "mdi-border-none-variant", - permission: "lesrooster.view_slots_rule", - }, - }, - { - path: "breaks/", - component: () => import("./components/Break.vue"), - name: "lesrooster.breaks", - meta: { - inMenu: true, - titleKey: "lesrooster.break.menu_title", - icon: "mdi-timer-sand-paused", - permission: "lesrooster.view_breaks_rule", - }, - }, - { - path: "timebound_course_configs/", - component: () => import("./components/TimeboundCourseConfigCRUDTable.vue"), - name: "lesrooster.timeboundCourseConfigs", - meta: { - inMenu: true, - titleKey: "lesrooster.timebound_course_config.crud_table_menu_title", - icon: "mdi-timetable", - permission: "lesrooster.view_timebound_course_configs_rule", - }, - }, - { - path: "timebound_course_configs/plan_courses/", - component: () => import("./components/TimeboundCourseConfigRaster.vue"), - name: "lesrooster.planCourses", - meta: { - inMenu: true, - titleKey: "lesrooster.timebound_course_config.raster_menu_title", - icon: "mdi-clock-edit-outline", - permission: "lesrooster.view_timebound_course_configs_rule", - }, - }, - ] + ], }; diff --git a/aleksis/apps/lesrooster/frontend/messages/de.json b/aleksis/apps/lesrooster/frontend/messages/de.json index 304c1e6f..849b3035 100644 --- a/aleksis/apps/lesrooster/frontend/messages/de.json +++ b/aleksis/apps/lesrooster/frontend/messages/de.json @@ -24,7 +24,7 @@ "menu_title": "Stundenraster" } }, - "actions":{ + "actions": { "copy_to_day": "Zu anderem Tag übernehmen" } -} \ No newline at end of file +} diff --git a/aleksis/apps/lesrooster/frontend/messages/en.json b/aleksis/apps/lesrooster/frontend/messages/en.json index 86cc2803..bd0377ed 100644 --- a/aleksis/apps/lesrooster/frontend/messages/en.json +++ b/aleksis/apps/lesrooster/frontend/messages/en.json @@ -63,7 +63,7 @@ "for_group": "Timetable management for group {group}" } }, - "actions":{ + "actions": { "copy_to_day": "Copy to another day" } } diff --git a/aleksis/apps/lesrooster/models.py b/aleksis/apps/lesrooster/models.py index cc6fce20..d02fdfb3 100644 --- a/aleksis/apps/lesrooster/models.py +++ b/aleksis/apps/lesrooster/models.py @@ -542,7 +542,9 @@ class TimeboundCourseConfig(ExtensibleModel): ) scheduled_slot_count = models.PositiveSmallIntegerField( - verbose_name=_("Number of slots this course is scheduled to fill per week"), blank=True, null=True + verbose_name=_("Number of slots this course is scheduled to fill per week"), + blank=True, + null=True, ) teachers = models.ManyToManyField( Person, diff --git a/aleksis/apps/lesrooster/schema/__init__.py b/aleksis/apps/lesrooster/schema/__init__.py index 03493d11..9ba9a898 100644 --- a/aleksis/apps/lesrooster/schema/__init__.py +++ b/aleksis/apps/lesrooster/schema/__init__.py @@ -8,26 +8,25 @@ from aleksis.apps.cursus.schema import Query as CursusSchemaQuery from aleksis.core.models import Group, Person from aleksis.core.schema.base import FilterOrderList from aleksis.core.schema.group import GroupType -from aleksis.core.schema.person import PersonType, PERSON_TYPE_FIELDS +from aleksis.core.schema.person import PERSON_TYPE_FIELDS, PersonType -from ..models import Slot +from ..models import Slot, ValidityRange from .break_type import ( + BreakSlotBatchCreateMutation, + BreakSlotBatchDeleteMutation, BreakSlotBatchPatchMutation, BreakSlotCreateMutation, BreakSlotDeleteMutation, BreakSlotType, - BreakSlotBatchCreateMutation, - BreakSlotBatchDeleteMutation, - BreakSlotBatchPatchMutation ) from .slot import ( CarryOverSlotsMutation, - SlotType, - SlotCreateMutation, - SlotDeleteMutation, SlotBatchCreateMutation, SlotBatchDeleteMutation, SlotBatchPatchMutation, + SlotCreateMutation, + SlotDeleteMutation, + SlotType, ) from .timebound_course_config import ( LesroosterExtendedSubjectType, @@ -38,14 +37,12 @@ from .timebound_course_config import ( TimeboundCourseConfigType, ) from .validity_range import ( + ValidityRangeBatchDeleteMutation, ValidityRangeBatchPatchMutation, ValidityRangeCreateMutation, ValidityRangeDeleteMutation, ValidityRangeType, - ValidityRangeBatchDeleteMutation, - ValidityRangeBatchPatchMutation ) -from ..models import Slot, ValidityRange class LesroosterExtendedPersonType(PersonType): @@ -99,7 +96,11 @@ class Query(graphene.ObjectType): @staticmethod def resolve_classes_by_grade(root, info, grade): grade_group = Group.objects.prefetch_related("child_groups").get(id=grade) - return get_objects_for_user(info.context.user, "core.view_group", grade_group.child_groups.filter(group_type__name="School class")) + return get_objects_for_user( + info.context.user, + "core.view_group", + grade_group.child_groups.filter(group_type__name="School class"), + ) @staticmethod def resolve_lesrooster_extended_teachers(root, info): diff --git a/aleksis/apps/lesrooster/schema/break_type.py b/aleksis/apps/lesrooster/schema/break_type.py index f159fccd..fd6306fe 100644 --- a/aleksis/apps/lesrooster/schema/break_type.py +++ b/aleksis/apps/lesrooster/schema/break_type.py @@ -10,8 +10,8 @@ from graphene_django_cud.mutations import ( from aleksis.core.schema.base import ( DeleteMutation, DjangoFilterMixin, - PermissionBatchPatchMixin, PermissionBatchDeleteMixin, + PermissionBatchPatchMixin, PermissionsTypeMixin, ) @@ -27,7 +27,15 @@ class BreakSlotType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectType): class Meta: model = Break - fields = ("id", "validity_range", "name", "weekday", "period_after", "time_start", "time_end") + fields = ( + "id", + "validity_range", + "name", + "weekday", + "period_after", + "time_start", + "time_end", + ) filter_fields = break_filters @classmethod @@ -52,9 +60,7 @@ class BreakSlotBatchCreateMutation(PermissionBatchPatchMixin, DjangoBatchCreateM class Meta: model = Break return_field_name = "breakSlots" - field_types = { - "weekday": graphene.Int() - } + field_types = {"weekday": graphene.Int()} permissions = ("",) # FIXME diff --git a/aleksis/apps/lesrooster/schema/lesson.py b/aleksis/apps/lesrooster/schema/lesson.py index 568c7ac1..bdd13cfc 100644 --- a/aleksis/apps/lesrooster/schema/lesson.py +++ b/aleksis/apps/lesrooster/schema/lesson.py @@ -1,13 +1,18 @@ from graphene_django.types import DjangoObjectType -from graphene_django_cud.mutations import DjangoBatchDeleteMutation, DjangoBatchPatchMutation, DjangoCreateMutation +from graphene_django_cud.mutations import ( + DjangoBatchDeleteMutation, + DjangoBatchPatchMutation, + DjangoCreateMutation, +) from aleksis.core.schema.base import ( DeleteMutation, DjangoFilterMixin, - PermissionBatchPatchMixin, PermissionBatchDeleteMixin, + PermissionBatchPatchMixin, PermissionsTypeMixin, ) + from ..models import Lesson diff --git a/aleksis/apps/lesrooster/schema/slot.py b/aleksis/apps/lesrooster/schema/slot.py index 0db0f3ab..9d06cb21 100644 --- a/aleksis/apps/lesrooster/schema/slot.py +++ b/aleksis/apps/lesrooster/schema/slot.py @@ -1,4 +1,5 @@ from django.db.models import Q + import graphene from graphene_django.types import DjangoObjectType from graphene_django_cud.mutations import ( @@ -11,10 +12,11 @@ from graphene_django_cud.mutations import ( from aleksis.core.schema.base import ( DeleteMutation, DjangoFilterMixin, - PermissionBatchPatchMixin, PermissionBatchDeleteMixin, + PermissionBatchPatchMixin, PermissionsTypeMixin, ) + from ..models import Break, Slot, ValidityRange slot_filters = { @@ -65,9 +67,7 @@ class SlotDeleteMutation(DeleteMutation): class SlotBatchCreateMutation(PermissionBatchPatchMixin, DjangoBatchCreateMutation): class Meta: model = Slot - field_types = { - "weekday": graphene.Int() - } + field_types = {"weekday": graphene.Int()} permissions = ("",) # FIXME @@ -116,11 +116,7 @@ class CarryOverSlotsMutation(graphene.Mutation): slot: Break | Slot klass = slot.get_real_instance_class() - defaults = { - "name": slot.name, - "time_start": slot.time_start, - "time_end": slot.time_end - } + defaults = {"name": slot.name, "time_start": slot.time_start, "time_end": slot.time_end} if hasattr(slot, "period_after"): defaults["period_after"] = slot.period_after @@ -130,20 +126,13 @@ class CarryOverSlotsMutation(graphene.Mutation): periods.append(slot.period) klass.objects.update_or_create( - weekday=to_day, - validity_range=validity_range, - period=slot.period, - defaults=defaults + weekday=to_day, validity_range=validity_range, period=slot.period, defaults=defaults ) if not only or not len(only): objects_to_delete = Slot.objects.filter( - weekday=to_day, - validity_range=validity_range - ).exclude( - Q(Slot___period__in=periods) - | Q(Break___period_after__in=periods_after) - ) + weekday=to_day, validity_range=validity_range + ).exclude(Q(Slot___period__in=periods) | Q(Break___period_after__in=periods_after)) objects_to_delete.delete() deleted = objects_to_delete.values_list("id", flat=True) @@ -153,5 +142,7 @@ class CarryOverSlotsMutation(graphene.Mutation): return CarryOverSlotsMutation( deleted=deleted, - result=Slot.objects.filter(weekday=to_day, validity_range=validity_range).non_polymorphic(), + result=Slot.objects.filter( + weekday=to_day, validity_range=validity_range + ).non_polymorphic(), ) diff --git a/aleksis/apps/lesrooster/schema/timebound_course_config.py b/aleksis/apps/lesrooster/schema/timebound_course_config.py index 0b41ae7a..6d6a5f24 100644 --- a/aleksis/apps/lesrooster/schema/timebound_course_config.py +++ b/aleksis/apps/lesrooster/schema/timebound_course_config.py @@ -1,7 +1,11 @@ import graphene from graphene_django import DjangoListField from graphene_django.types import DjangoObjectType -from graphene_django_cud.mutations import DjangoBatchCreateMutation, DjangoBatchPatchMutation, DjangoCreateMutation +from graphene_django_cud.mutations import ( + DjangoBatchCreateMutation, + DjangoBatchPatchMutation, + DjangoCreateMutation, +) from guardian.shortcuts import get_objects_for_user from aleksis.apps.cursus.models import Course, Subject diff --git a/aleksis/apps/lesrooster/schema/validity_range.py b/aleksis/apps/lesrooster/schema/validity_range.py index e56765f0..f8d7a663 100644 --- a/aleksis/apps/lesrooster/schema/validity_range.py +++ b/aleksis/apps/lesrooster/schema/validity_range.py @@ -1,11 +1,15 @@ from graphene_django.types import DjangoObjectType -from graphene_django_cud.mutations import DjangoBatchDeleteMutation, DjangoBatchPatchMutation, DjangoCreateMutation +from graphene_django_cud.mutations import ( + DjangoBatchDeleteMutation, + DjangoBatchPatchMutation, + DjangoCreateMutation, +) from aleksis.core.schema.base import ( DeleteMutation, DjangoFilterMixin, - PermissionBatchPatchMixin, PermissionBatchDeleteMixin, + PermissionBatchPatchMixin, PermissionsTypeMixin, ) -- GitLab