From 22dcf78c2129ec10c79378dce0ff9b0e5ac08d9b Mon Sep 17 00:00:00 2001 From: magicfelix <felix@felix-zauberer.de> Date: Tue, 13 Feb 2024 21:41:14 +0100 Subject: [PATCH 01/17] WIP: Adapt to refactored CRUD lists --- .../components/breaks_and_slots/Break.vue | 19 ++++---- .../breaks_and_slots/LesroosterSlot.vue | 20 ++++----- .../components/breaks_and_slots/break.graphql | 32 -------------- .../components/breaks_and_slots/slot.graphql | 32 -------------- .../components/lesson_raster/LessonRaster.vue | 36 +++------------- .../components/supervision/Supervision.vue | 22 +++++----- .../supervision/supervision.graphql | 14 ------ .../TimeboundCourseConfigCRUDTable.vue | 23 +++++----- .../TimeboundCourseConfigRaster.vue | 10 ++--- .../timeboundCourseConfig.graphql | 24 ++--------- .../timetableManagement.graphql | 16 +++---- .../validity_range/ValidityRange.vue | 22 ++++------ .../validity_range/ValidityRangeField.vue | 13 +++--- .../validity_range/validityRange.graphql | 12 ++---- aleksis/apps/lesrooster/schema/__init__.py | 43 ++++++------------- aleksis/apps/lesrooster/schema/break_slot.py | 24 ----------- aleksis/apps/lesrooster/schema/lesson.py | 32 +------------- aleksis/apps/lesrooster/schema/slot.py | 15 ------- aleksis/apps/lesrooster/schema/supervision.py | 10 +---- aleksis/apps/lesrooster/schema/time_grid.py | 10 +---- .../schema/timebound_course_config.py | 15 ++----- .../apps/lesrooster/schema/validity_range.py | 10 +---- pyproject.toml | 2 +- 23 files changed, 104 insertions(+), 352 deletions(-) diff --git a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue index b1b6156e..52bf8e28 100644 --- a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue +++ b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue @@ -1,8 +1,7 @@ <script> import { breakSlots, - createBreakSlot, - deleteBreakSlot, + createBreakSlots, deleteBreakSlots, updateBreakSlots, } from "./break.graphql"; @@ -39,15 +38,13 @@ export default { i18nKey: "lesrooster.break", createItemI18nKey: "lesrooster.break.create_item", gqlQuery: breakSlots, - gqlCreateMutation: createBreakSlot, + gqlCreateMutation: createBreakSlots, gqlPatchMutation: updateBreakSlots, - gqlDeleteMutation: deleteBreakSlot, - gqlDeleteMultipleMutation: deleteBreakSlots, + gqlDeleteMutation: deleteBreakSlots, }; }, methods: { getCreateData(item) { - console.log("in getCreateData", item); return { ...item, period: null, @@ -55,17 +52,17 @@ export default { timeGrid: item.timeGrid.id, }; }, - getPatchData(items) { - console.log("patch items", items); - return items.map((item) => ({ + getPatchData(item) { + item = { id: item.id, name: item.name, weekday: this.weekdayAsInt(item.weekday), period: null, timeStart: item.timeStart, timeEnd: item.timeEnd, - timeGrid: item.timeGrid.id, - })); + timeGrid: item.timeGrid?.id, + }; + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); }, }, }; diff --git a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue index 19189786..cb6f55cb 100644 --- a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue +++ b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue @@ -15,7 +15,6 @@ import TimeGridField from "../validity_range/TimeGridField.vue"; :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" @@ -116,8 +115,7 @@ import TimeGridField from "../validity_range/TimeGridField.vue"; <script> import { slots, - createSlot, - deleteSlot, + createSlots, deleteSlots, updateSlots, } from "./slot.graphql"; @@ -156,10 +154,9 @@ export default { i18nKey: "lesrooster.slot", createItemI18nKey: "lesrooster.slot.create_slot", gqlQuery: slots, - gqlCreateMutation: createSlot, + gqlCreateMutation: createSlots, gqlPatchMutation: updateSlots, - gqlDeleteMutation: deleteSlot, - gqlDeleteMultipleMutation: deleteSlots, + gqlDeleteMutation: deleteSlots, defaultItem: { name: "", timeStart: "", @@ -185,24 +182,23 @@ export default { return NaN; }, getCreateData(item) { - console.log("in getCreateData", item); return { ...item, weekday: this.weekdayAsInt(item.weekday), timeGrid: item.timeGrid.id, }; }, - getPatchData(items) { - console.log("patch items", items); - return items.map((item) => ({ + getPatchData(item) { + item = { id: item.id, name: item.name, weekday: this.weekdayAsInt(item.weekday), period: item.period, timeStart: item.timeStart, timeEnd: item.timeEnd, - timeGrid: item.timeGrid.id, - })); + timeGrid: item.timeGrid?.id, + }; + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); }, formatTimeGrid(item) { if (!item) return null; diff --git a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/break.graphql b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/break.graphql index 63c2087d..8a764a73 100644 --- a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/break.graphql +++ b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/break.graphql @@ -24,32 +24,6 @@ query breakSlots($orderBy: [String], $filters: JSONString) { } } -mutation createBreakSlot($input: CreateBreakSlotInput!) { - createBreakSlot(input: $input) { - item: breakSlot { - id - name - timeGrid { - id - group { - id - name - } - validityRange { - id - name - } - } - weekday - period - timeStart - timeEnd - canEdit - canDelete - } - } -} - mutation createBreakSlots($input: [BatchCreateBreakSlotInput]!) { createBreakSlots(input: $input) { items: breakSlots { @@ -77,12 +51,6 @@ mutation createBreakSlots($input: [BatchCreateBreakSlotInput]!) { } } -mutation deleteBreakSlot($id: ID!) { - deleteBreakSlot(id: $id) { - ok - } -} - mutation deleteBreakSlots($ids: [ID]!) { deleteBreakSlots(ids: $ids) { deletionCount diff --git a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/slot.graphql b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/slot.graphql index 269faa53..3c6b2362 100644 --- a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/slot.graphql +++ b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/slot.graphql @@ -23,32 +23,6 @@ query slots($orderBy: [String], $filters: JSONString) { } } -mutation createSlot($input: CreateSlotInput!) { - createSlot(input: $input) { - item: slot { - id - name - timeGrid { - id - group { - id - name - } - validityRange { - id - name - } - } - weekday - period - timeStart - timeEnd - canEdit - canDelete - } - } -} - mutation createSlots($input: [BatchCreateSlotInput]!) { createSlots(input: $input) { items: slots { @@ -76,12 +50,6 @@ mutation createSlots($input: [BatchCreateSlotInput]!) { } } -mutation deleteSlot($id: ID!) { - deleteSlot(id: $id) { - ok - } -} - mutation deleteSlots($ids: [ID]!) { deleteSlots(ids: $ids) { deletionCount diff --git a/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue b/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue index 02860dc8..bc50cbe0 100644 --- a/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue +++ b/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue @@ -180,28 +180,12 @@ <delete-dialog :gql-mutation="deleteMutation" :gql-query="$apollo.queries.items" - v-model="deleteDialog" - :item="itemToDelete" - > - <template #body> - {{ - $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" + v-model="deleteDialog" > <template #title> {{ - $t("lesrooster.slot.confirm_delete_multiple_slots", { + $t("lesrooster.slot.confirm_delete_slots", { day: $t("weekdays." + weekdayToDelete), }) }} @@ -214,7 +198,7 @@ </li> </ul> </template> - </delete-multiple-dialog> + </delete-dialog> </div> </template> @@ -223,11 +207,9 @@ import { carryOverSlots, copySlotsFromGrid, slots, - deleteSlot, deleteSlots, } from "../breaks_and_slots/slot.graphql"; import DeleteDialog from "aleksis.core/components/generic/dialogs/DeleteDialog.vue"; -import DeleteMultipleDialog from "aleksis.core/components/generic/dialogs/DeleteMultipleDialog.vue"; import CopyFromTimeGridMenu from "../validity_range/CopyFromTimeGridMenu.vue"; import SlotCard from "./SlotCard.vue"; import SlotCreator from "./SlotCreator.vue"; @@ -240,7 +222,6 @@ export default { CopyFromTimeGridMenu, SlotCreator, DeleteDialog, - DeleteMultipleDialog, SlotCard, }, apollo: { @@ -272,11 +253,8 @@ export default { main: false, }, gqlQuery: slots, - deleteMutation: deleteSlot, - deleteMultipleMutation: deleteSlots, + deleteMutation: deleteSlots, deleteDialog: false, - deleteMultipleDialog: false, - itemToDelete: null, itemsToDelete: [], weekdayToDelete: "", createBreaks: false, @@ -426,8 +404,8 @@ export default { this.loading[day] = false; }); }, - deleteSingularSlot(slot) { - this.itemToDelete = slot; + deleteSlot(slot) { + this.itemToDeletes = [slot] this.deleteDialog = true; }, deleteSlotsOfDay(weekday) { @@ -435,7 +413,7 @@ export default { (slot) => slot.weekday === weekday, ); this.weekdayToDelete = weekday; - this.deleteMultipleDialog = true; + this.deleteDialog = true; }, copyFromGrid(existingTimeGrid) { if (!this.internalTimeGrid || !this.internalTimeGrid.id) return; diff --git a/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue b/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue index 730c1bfc..200e0150 100644 --- a/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue +++ b/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue @@ -15,7 +15,6 @@ import InlineCRUDList from "aleksis.core/components/generic/InlineCRUDList.vue"; :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" @@ -150,8 +149,7 @@ import InlineCRUDList from "aleksis.core/components/generic/InlineCRUDList.vue"; <script> import { supervisions, - createSupervision, - deleteSupervision, + createSupervisions, deleteSupervisions, updateSupervisions, } from "./supervision.graphql"; @@ -191,10 +189,9 @@ export default { i18nKey: "lesrooster.supervision", createItemI18nKey: "lesrooster.supervision.create_supervision", gqlQuery: supervisions, - gqlCreateMutation: createSupervision, + gqlCreateMutation: createSupervisions, gqlPatchMutation: updateSupervisions, - gqlDeleteMutation: deleteSupervision, - gqlDeleteMultipleMutation: deleteSupervisions, + gqlDeleteMutation: deleteSupervisions, defaultItem: { breakSlot: null, teachers: [], @@ -298,15 +295,16 @@ export default { recurrence: this.getRRule(item.breakSlot.timeGrid).toString(), }; }, - getPatchData(items) { - return items.map((item) => ({ + getPatchData(item) { + item = { id: item.id, - breakSlot: item.breakSlot.id, - rooms: item.rooms.map((r) => r.id), - teachers: item.teachers.map((t) => t.id), + breakSlot: item.breakSlot?.id, + rooms: item.rooms?.map((r) => r.id), + teachers: item.teachers?.map((t) => t.id), subject: item.subject?.id, recurrence: this.getRRule(item.breakSlot.timeGrid).toString(), - })); + }; + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); }, }, }; diff --git a/aleksis/apps/lesrooster/frontend/components/supervision/supervision.graphql b/aleksis/apps/lesrooster/frontend/components/supervision/supervision.graphql index 26556dfe..c37ad32d 100644 --- a/aleksis/apps/lesrooster/frontend/components/supervision/supervision.graphql +++ b/aleksis/apps/lesrooster/frontend/components/supervision/supervision.graphql @@ -47,14 +47,6 @@ query supervisions($orderBy: [String], $filters: JSONString) { } } -mutation createSupervision($input: CreateSupervisionInput!) { - createSupervision(input: $input) { - item: supervision { - ...supervisionFields - } - } -} - mutation createSupervisions($input: [BatchCreateSupervisionInput]!) { createSupervisions(input: $input) { items: supervisions { @@ -63,12 +55,6 @@ mutation createSupervisions($input: [BatchCreateSupervisionInput]!) { } } -mutation deleteSupervision($id: ID!) { - deleteSupervision(id: $id) { - ok - } -} - mutation deleteSupervisions($ids: [ID]!) { deleteSupervisions(ids: $ids) { deletionCount diff --git a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue index bf93ef62..814b3258 100644 --- a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue +++ b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue @@ -136,8 +136,8 @@ import SubjectChip from "aleksis.apps.cursus/components/SubjectChip.vue"; <script> import { timeboundCourseConfigs, - createTimeboundCourseConfig, - deleteTimeboundCourseConfig, + createTimeboundCourseConfigs, + deleteTimeboundCourseConfigs, updateTimeboundCourseConfigs, } from "./timeboundCourseConfig.graphql"; @@ -172,9 +172,9 @@ export default { createItemI18nKey: "lesrooster.timebound_course_config.create_timebound_course_config", gqlQuery: timeboundCourseConfigs, - gqlCreateMutation: createTimeboundCourseConfig, + gqlCreateMutation: createTimeboundCourseConfigs, gqlPatchMutation: updateTimeboundCourseConfigs, - gqlDeleteMutation: deleteTimeboundCourseConfig, + gqlDeleteMutation: deleteTimeboundCourseConfigs, defaultItem: { course: { id: "", @@ -192,7 +192,6 @@ export default { }, methods: { getCreateData(item) { - console.log("in getCreateData", item); return { ...item, course: item.course.id, @@ -200,15 +199,15 @@ export default { validityRange: item.validityRange.id, }; }, - getPatchData(items) { - console.log("patch items", items); - return items.map((item) => ({ + getPatchData(item) { + item = { id: item.id, - course: item.course.id, - teachers: item.teachers.map((t) => t.id), - validityRange: item.validityRange.id, + course: item.course?.id, + teachers: item.teachers?.map((t) => t.id), + validityRange: item.validityRange?.id, lessonQuota: item.lessonQuota, - })); + }; + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); }, }, apollo: { diff --git a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigRaster.vue b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigRaster.vue index 7a0a700a..79715008 100644 --- a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigRaster.vue +++ b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigRaster.vue @@ -188,7 +188,7 @@ import SubjectChip from "aleksis.apps.cursus/components/SubjectChip.vue"; <script> import { subjects, - batchCreateTimeboundCourseConfig, + createTimeboundCourseConfigs, updateTimeboundCourseConfigs, } from "./timeboundCourseConfig.graphql"; @@ -196,7 +196,7 @@ import { currentValidityRange as gqlCurrentValidityRange } from "../validity_ran import { gqlGroups, gqlTeachers } from "../helper.graphql"; -import { batchCreateCourse } from "aleksis.apps.cursus/components/course.graphql"; +import { createCourses } from "aleksis.apps.cursus/components/course.graphql"; export default { name: "TimeboungCourseConfigRaster", @@ -269,7 +269,7 @@ export default { } } else { if ( - !course.lrTimeboundCourseConfigs.filter( + !course.lrTimeboundCourseConfigs?.filter( (c) => c.validityRange.id === this.internalValidityRange?.id, ).length ) { @@ -312,11 +312,11 @@ export default { }, { data: this.createdCourseConfigs, - mutation: batchCreateTimeboundCourseConfig, + mutation: createTimeboundCourseConfigs, }, { data: this.createdCourses, - mutation: batchCreateCourse, + mutation: createCourses, }, ]) { if (mutationCombination.data.length) { diff --git a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql index 9ede745e..044a2be2 100644 --- a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql +++ b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql @@ -55,26 +55,10 @@ query timeboundCourseConfigs($orderBy: [String], $filters: JSONString) { } } -mutation createTimeboundCourseConfig( - $input: CreateTimeboundCourseConfigInput! -) { - createTimeboundCourseConfig(input: $input) { - item: timeboundCourseConfig { - ...timeboundCourseConfigFields - course { - ...courseFields - subject { - ...subjectFields - } - } - } - } -} - -mutation batchCreateTimeboundCourseConfig( +mutation createTimeboundCourseConfigs( $input: [BatchCreateTimeboundCourseConfigInput]! ) { - batchCreateTimeboundCourseConfig(input: $input) { + createTimeboundCourseConfigs(input: $input) { item: timeboundCourseConfigs { ...timeboundCourseConfigFields course { @@ -87,8 +71,8 @@ mutation batchCreateTimeboundCourseConfig( } } -mutation deleteTimeboundCourseConfig($id: ID!) { - deleteTimeboundCourseConfig(id: $id) { +mutation deleteTimeboundCourseConfigs($ids: [ID]!) { + deleteTimeboundCourseConfigs(ids: $ids) { ok } } diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql b/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql index 970c1c0b..3c6a73a6 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql @@ -138,9 +138,9 @@ query overlayLessons($rooms: [ID]!, $teachers: [ID]!, $timeGrid: ID!) { } } -mutation createLesson($input: CreateLessonInput!) { - createLesson(input: $input) { - lesson { +mutation createLessons($input: [BatchCreateLessonInput]!) { + createLessons(input: $input) { + items: lessons { id slotStart { id @@ -217,9 +217,9 @@ mutation moveLesson($id: ID!, $input: PatchLessonInput!) { } } -mutation updateLesson($input: PatchLessonInput!, $id: ID!) { - updateLesson(id: $id, input: $input) { - item: lesson { +mutation updateLessons($input: [BatchPatchLessonInput]!) { + updateLessons(input: $input) { + items: lessons { id subject { id @@ -245,8 +245,8 @@ mutation updateLesson($input: PatchLessonInput!, $id: ID!) { } } -mutation deleteLesson($id: ID!) { - deleteLesson(id: $id) { +mutation deleteLesson($ids: [ID]!) { + deleteLessons(ids: $ids) { ok } } diff --git a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue index b203b9d7..1dbf398e 100644 --- a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue +++ b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue @@ -21,7 +21,6 @@ import ValidityRangeStatusChip from "./ValidityRangeStatusChip.vue"; :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" @@ -210,8 +209,7 @@ import ValidityRangeStatusChip from "./ValidityRangeStatusChip.vue"; <script> import { validityRanges, - createValidityRange, - deleteValidityRange, + createValidityRanges, deleteValidityRanges, updateValidityRanges, createTimeGrid, @@ -253,10 +251,9 @@ export default { ], i18nKey: "lesrooster.validity_range", gqlQuery: validityRanges, - gqlCreateMutation: createValidityRange, + gqlCreateMutation: createValidityRanges, gqlPatchMutation: updateValidityRanges, - gqlDeleteMutation: deleteValidityRange, - gqlDeleteMultipleMutation: deleteValidityRanges, + gqlDeleteMutation: deleteValidityRanges, defaultItem: { name: "", dateStart: "", @@ -313,22 +310,21 @@ export default { }, methods: { getCreateData(item) { - console.log("in getCreateData", item); return { ...item, schoolTerm: item.schoolTerm?.id, }; }, - getPatchData(items) { - console.log("patch items", items); - return items.map((item) => ({ + getPatchData(item) { + item = { id: item.id, name: item.name, dateStart: item.dateStart, dateEnd: item.dateEnd, - schoolTerm: item.schoolTerm.id, - status: item.status.toLowerCase(), - })); + schoolTerm: item.schoolTerm?.id, + status: item.status?.toLowerCase(), + }; + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); }, createTimeGridFor(validityRange) { this.timeGrids.range = validityRange; diff --git a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue index 274df9db..c1aaa47a 100644 --- a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue +++ b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue @@ -59,7 +59,7 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField </template> <script> -import { validityRanges, createValidityRange } from "./validityRange.graphql"; +import { validityRanges, createValidityRanges } from "./validityRange.graphql"; export default { name: "ValidityRangeField", @@ -85,7 +85,7 @@ export default { ], i18nKey: "lesrooster.validity_range", gqlQuery: validityRanges, - gqlCreateMutation: createValidityRange, + gqlCreateMutation: createValidityRanges, defaultItem: { name: "", dateStart: "", @@ -97,21 +97,20 @@ export default { }, methods: { getCreateData(item) { - console.log("in getCreateData", item); return { ...item, schoolTerm: item.schoolTerm?.id, }; }, - getPatchData(items) { - console.log("patch items", items); - return items.map((item) => ({ + getPatchData(item) { + item = { id: item.id, name: item.name, dateStart: item.dateStart, dateEnd: item.dateEnd, schoolTerm: item.schoolTerm.id, - })); + }; + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); }, }, }; diff --git a/aleksis/apps/lesrooster/frontend/components/validity_range/validityRange.graphql b/aleksis/apps/lesrooster/frontend/components/validity_range/validityRange.graphql index 5c15b259..d698ab15 100644 --- a/aleksis/apps/lesrooster/frontend/components/validity_range/validityRange.graphql +++ b/aleksis/apps/lesrooster/frontend/components/validity_range/validityRange.graphql @@ -22,9 +22,9 @@ query validityRanges($orderBy: [String], $filters: JSONString) { } } -mutation createValidityRange($input: CreateValidityRangeInput!) { - createValidityRange(input: $input) { - item: validityRange { +mutation createValidityRanges($input: [BatchCreateValidityRangeInput]!) { + createValidityRanges(input: $input) { + items: validityRanges { id name status @@ -48,12 +48,6 @@ mutation createValidityRange($input: CreateValidityRangeInput!) { } } -mutation deleteValidityRange($id: ID!) { - deleteValidityRange(id: $id) { - ok - } -} - mutation deleteValidityRanges($ids: [ID]!) { deleteValidityRanges(ids: $ids) { deletionCount diff --git a/aleksis/apps/lesrooster/schema/__init__.py b/aleksis/apps/lesrooster/schema/__init__.py index ca317010..a5912290 100644 --- a/aleksis/apps/lesrooster/schema/__init__.py +++ b/aleksis/apps/lesrooster/schema/__init__.py @@ -24,16 +24,12 @@ from .break_slot import ( BreakSlotBatchCreateMutation, BreakSlotBatchDeleteMutation, BreakSlotBatchPatchMutation, - BreakSlotCreateMutation, - BreakSlotDeleteMutation, BreakSlotType, ) from .lesson import ( + LessonBatchCreateMutation, LessonBatchDeleteMutation, LessonBatchPatchMutation, - LessonCreateMutation, - LessonDeleteMutation, - LessonPatchMutation, LessonType, ) from .slot import ( @@ -42,36 +38,31 @@ from .slot import ( SlotBatchCreateMutation, SlotBatchDeleteMutation, SlotBatchPatchMutation, - SlotCreateMutation, - SlotDeleteMutation, SlotType, ) from .supervision import ( + SupervisionBatchCreateMutation, SupervisionBatchDeleteMutation, SupervisionBatchPatchMutation, - SupervisionCreateMutation, - SupervisionDeleteMutation, SupervisionType, ) from .time_grid import ( + TimeGridBatchCreateMutation, + TimeGridBatchDeleteMutation, TimeGridBatchDeleteMutation, - TimeGridCreateMutation, - TimeGridDeleteMutation, TimeGridType, ) from .timebound_course_config import ( LesroosterExtendedSubjectType, TimeboundCourseConfigBatchCreateMutation, + TimeboundCourseConfigBatchDeleteMutation, TimeboundCourseConfigBatchPatchMutation, - TimeboundCourseConfigCreateMutation, - TimeboundCourseConfigDeleteMutation, TimeboundCourseConfigType, ) from .validity_range import ( + ValidityRangeBatchCreateMutation, ValidityRangeBatchDeleteMutation, ValidityRangeBatchPatchMutation, - ValidityRangeCreateMutation, - ValidityRangeDeleteMutation, ValidityRangeType, ) @@ -277,42 +268,32 @@ class Query(graphene.ObjectType): class Mutation(graphene.ObjectType): - create_break_slot = BreakSlotCreateMutation.Field() create_break_slots = BreakSlotBatchCreateMutation.Field() - delete_break_slot = BreakSlotDeleteMutation.Field() delete_break_slots = BreakSlotBatchDeleteMutation.Field() update_break_slots = BreakSlotBatchPatchMutation.Field() - create_slot = SlotCreateMutation.Field() create_slots = SlotBatchCreateMutation.Field() - delete_slot = SlotDeleteMutation.Field() delete_slots = SlotBatchDeleteMutation.Field() update_slots = SlotBatchPatchMutation.Field() - batch_create_timebound_course_config = TimeboundCourseConfigBatchCreateMutation.Field() - create_timebound_course_config = TimeboundCourseConfigCreateMutation.Field() - delete_timebound_course_config = TimeboundCourseConfigDeleteMutation.Field() + create_timebound_course_configs = TimeboundCourseConfigBatchCreateMutation.Field() + delete_timebound_course_configs = TimeboundCourseConfigBatchDeleteMutation.Field() update_timebound_course_configs = TimeboundCourseConfigBatchPatchMutation.Field() carry_over_slots = CarryOverSlotsMutation.Field() copy_slots_from_grid = CopySlotsFromDifferentTimeGridMutation.Field() - create_validity_range = ValidityRangeCreateMutation.Field() - delete_validity_range = ValidityRangeDeleteMutation.Field() + create_validity_ranges = ValidityRangeBatchCreateMutation.Field() delete_validity_ranges = ValidityRangeBatchDeleteMutation.Field() update_validity_ranges = ValidityRangeBatchPatchMutation.Field() - create_time_grid = TimeGridCreateMutation.Field() - delete_time_grid = TimeGridDeleteMutation.Field() + create_time_grids = TimeGridBatchCreateMutation.Field() delete_time_grids = TimeGridBatchDeleteMutation.Field() update_time_grids = TimeGridBatchDeleteMutation.Field() - create_lesson = LessonCreateMutation.Field() - delete_lesson = LessonDeleteMutation.Field() + create_lessons = LessonBatchCreateMutation.Field() delete_lessons = LessonBatchDeleteMutation.Field() - update_lesson = LessonPatchMutation.Field() update_lessons = LessonBatchPatchMutation.Field() - create_supervision = SupervisionCreateMutation.Field() - delete_supervision = SupervisionDeleteMutation.Field() + create_supervisions = SupervisionBatchCreateMutation.Field() delete_supervisions = SupervisionBatchDeleteMutation.Field() update_supervisions = SupervisionBatchPatchMutation.Field() diff --git a/aleksis/apps/lesrooster/schema/break_slot.py b/aleksis/apps/lesrooster/schema/break_slot.py index fbc54e41..ed6aa19e 100644 --- a/aleksis/apps/lesrooster/schema/break_slot.py +++ b/aleksis/apps/lesrooster/schema/break_slot.py @@ -4,12 +4,10 @@ from graphene_django_cud.mutations import ( DjangoBatchCreateMutation, DjangoBatchDeleteMutation, DjangoBatchPatchMutation, - DjangoCreateMutation, ) from guardian.shortcuts import get_objects_for_user from aleksis.core.schema.base import ( - DeleteMutation, DjangoFilterMixin, PermissionBatchDeleteMixin, PermissionBatchPatchMixin, @@ -45,28 +43,6 @@ class BreakSlotType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectType): return queryset -class BreakSlotCreateMutation(DjangoCreateMutation): - class Meta: - model = BreakSlot - return_field_name = "breakSlot" - field_types = {"weekday": graphene.Int()} - only_fields = ( - "id", - "time_grid", - "name", - "weekday", - "period", - "time_start", - "time_end", - ) - permissions = ("lesrooster.create_breakslot_rule",) - - -class BreakSlotDeleteMutation(DeleteMutation): - klass = BreakSlot - permission_required = "lesrooster.delete_breakslot_rule" - - class BreakSlotBatchCreateMutation(PermissionBatchPatchMixin, DjangoBatchCreateMutation): class Meta: model = BreakSlot diff --git a/aleksis/apps/lesrooster/schema/lesson.py b/aleksis/apps/lesrooster/schema/lesson.py index de013bc0..e9c87c77 100644 --- a/aleksis/apps/lesrooster/schema/lesson.py +++ b/aleksis/apps/lesrooster/schema/lesson.py @@ -1,16 +1,14 @@ import graphene from graphene_django.types import DjangoObjectType from graphene_django_cud.mutations import ( + DjangoBatchCreateMutation, DjangoBatchDeleteMutation, DjangoBatchPatchMutation, - DjangoCreateMutation, - DjangoPatchMutation, ) from guardian.shortcuts import get_objects_for_user from recurrence import Recurrence, deserialize, serialize from aleksis.core.schema.base import ( - DeleteMutation, DjangoFilterMixin, OptimisticResponseTypeMixin, PermissionBatchDeleteMixin, @@ -47,7 +45,7 @@ class LessonType( return serialize(root.recurrence) -class LessonCreateMutation(DjangoCreateMutation): +class LessonBatchCreateMutation(DjangoBatchCreateMutation): class Meta: model = Lesson only_fields = ( @@ -68,11 +66,6 @@ class LessonCreateMutation(DjangoCreateMutation): return deserialize(value) -class LessonDeleteMutation(DeleteMutation): - klass = Lesson - permission_required = "lesrooster.delete_lesson_rule" - - class LessonBatchDeleteMutation(PermissionBatchDeleteMixin, DjangoBatchDeleteMutation): class Meta: model = Lesson @@ -98,24 +91,3 @@ class LessonBatchPatchMutation(PermissionBatchPatchMixin, DjangoBatchPatchMutati @classmethod def handle_recurrence(cls, value: str, name, info) -> Recurrence: return deserialize(value) - - -class LessonPatchMutation(PermissionPatchMixin, DjangoPatchMutation): - class Meta: - model = Lesson - only_fields = ( - "id", - "course", - "slot_start", - "slot_end", - "rooms", - "teachers", - "subject", - "recurrence", - ) - field_types = {"recurrence": graphene.String()} - permissions = ("lesrooster.edit_lesson_rule",) - - @classmethod - def handle_recurrence(cls, value: str, name, info) -> Recurrence: - return deserialize(value) diff --git a/aleksis/apps/lesrooster/schema/slot.py b/aleksis/apps/lesrooster/schema/slot.py index 6c2de6a5..73f135a9 100644 --- a/aleksis/apps/lesrooster/schema/slot.py +++ b/aleksis/apps/lesrooster/schema/slot.py @@ -6,12 +6,10 @@ from graphene_django_cud.mutations import ( DjangoBatchCreateMutation, DjangoBatchDeleteMutation, DjangoBatchPatchMutation, - DjangoCreateMutation, ) from guardian.shortcuts import get_objects_for_user from aleksis.core.schema.base import ( - DeleteMutation, DjangoFilterMixin, PermissionBatchDeleteMixin, PermissionBatchPatchMixin, @@ -50,19 +48,6 @@ class SlotType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectType): return root.get_real_instance_class().__name__ -class SlotCreateMutation(DjangoCreateMutation): - class Meta: - model = Slot - field_types = {"weekday": graphene.Int()} - only_fields = ("id", "time_grid", "name", "weekday", "period", "time_start", "time_end") - permissions = ("lesrooster.create_slot_rule",) - - -class SlotDeleteMutation(DeleteMutation): - klass = Slot - permission_required = "lesrooster.delete_slot" - - class SlotBatchCreateMutation(PermissionBatchPatchMixin, DjangoBatchCreateMutation): class Meta: model = Slot diff --git a/aleksis/apps/lesrooster/schema/supervision.py b/aleksis/apps/lesrooster/schema/supervision.py index e028cf86..80603a12 100644 --- a/aleksis/apps/lesrooster/schema/supervision.py +++ b/aleksis/apps/lesrooster/schema/supervision.py @@ -1,15 +1,14 @@ import graphene from graphene_django.types import DjangoObjectType from graphene_django_cud.mutations import ( + DjangoBatchCreateMutation, DjangoBatchDeleteMutation, DjangoBatchPatchMutation, - DjangoCreateMutation, ) from guardian.shortcuts import get_objects_for_user from recurrence import Recurrence, deserialize, serialize from aleksis.core.schema.base import ( - DeleteMutation, DjangoFilterMixin, PermissionBatchDeleteMixin, PermissionBatchPatchMixin, @@ -53,7 +52,7 @@ class SupervisionType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectType) return serialize(root.recurrence) -class SupervisionCreateMutation(DjangoCreateMutation): +class SupervisionBatchCreateMutation(DjangoBatchCreateMutation): class Meta: model = Supervision field_types = {"recurrence": graphene.String()} @@ -72,11 +71,6 @@ class SupervisionCreateMutation(DjangoCreateMutation): return deserialize(value) -class SupervisionDeleteMutation(DeleteMutation): - klass = Supervision - permission_required = "lesrooster.delete_supervision_rule" - - class SupervisionBatchDeleteMutation(PermissionBatchDeleteMixin, DjangoBatchDeleteMutation): class Meta: model = Supervision diff --git a/aleksis/apps/lesrooster/schema/time_grid.py b/aleksis/apps/lesrooster/schema/time_grid.py index 906b16ce..a823920d 100644 --- a/aleksis/apps/lesrooster/schema/time_grid.py +++ b/aleksis/apps/lesrooster/schema/time_grid.py @@ -1,13 +1,12 @@ from graphene_django.types import DjangoObjectType from graphene_django_cud.mutations import ( + DjangoBatchCreateMutation, DjangoBatchDeleteMutation, DjangoBatchPatchMutation, - DjangoCreateMutation, ) from guardian.shortcuts import get_objects_for_user from aleksis.core.schema.base import ( - DeleteMutation, DjangoFilterMixin, PermissionBatchDeleteMixin, PermissionBatchPatchMixin, @@ -40,7 +39,7 @@ class TimeGridType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectType): return queryset -class TimeGridCreateMutation(DjangoCreateMutation): +class TimeGridBatchCreateMutation(DjangoBatchCreateMutation): class Meta: model = TimeGrid permissions = ("lesrooster.create_timegrid_rule",) @@ -51,11 +50,6 @@ class TimeGridCreateMutation(DjangoCreateMutation): ) -class TimeGridDeleteMutation(DeleteMutation): - klass = TimeGrid - permission_required = "lesrooster.delete_timegrid_rule" - - class TimeGridBatchDeleteMutation(PermissionBatchDeleteMixin, DjangoBatchDeleteMutation): class Meta: model = TimeGrid diff --git a/aleksis/apps/lesrooster/schema/timebound_course_config.py b/aleksis/apps/lesrooster/schema/timebound_course_config.py index 978260ba..705f08ec 100644 --- a/aleksis/apps/lesrooster/schema/timebound_course_config.py +++ b/aleksis/apps/lesrooster/schema/timebound_course_config.py @@ -2,15 +2,14 @@ import graphene from graphene_django.types import DjangoObjectType from graphene_django_cud.mutations import ( DjangoBatchCreateMutation, + DjangoBatchDeleteMutation, DjangoBatchPatchMutation, - DjangoCreateMutation, ) from guardian.shortcuts import get_objects_for_user from aleksis.apps.cursus.models import Course, Subject from aleksis.apps.cursus.schema import CourseInterface, CourseType, SubjectType from aleksis.core.schema.base import ( - DeleteMutation, DjangoFilterMixin, PermissionBatchPatchMixin, PermissionsTypeMixin, @@ -86,23 +85,17 @@ class LesroosterExtendedSubjectType(SubjectType): courses = graphene.List(LesroosterExtendedCourseType) -class TimeboundCourseConfigCreateMutation(DjangoCreateMutation): +class TimeboundCourseConfigBatchCreateMutation(DjangoBatchCreateMutation): class Meta: model = TimeboundCourseConfig fields = ("id", "course", "validity_range", "lesson_quota", "teachers") permissions = ("lesrooster.create_timeboundcourseconfig_rule",) -class TimeboundCourseConfigBatchCreateMutation(DjangoBatchCreateMutation): +class TimeboundCourseConfigBatchDeleteMutation(DjangoBatchDeleteMutation): class Meta: model = TimeboundCourseConfig - fields = ("id", "course", "validity_range", "lesson_quota", "teachers") - permissions = ("lesrooster.create_timeboundcourseconfig_rule",) - - -class TimeboundCourseConfigDeleteMutation(DeleteMutation): - klass = TimeboundCourseConfig - permission_required = "lesrooster.delete_timeboundcourseconfig_rule" + permission_required = "lesrooster.delete_timeboundcourseconfig_rule" class TimeboundCourseConfigBatchPatchMutation(PermissionBatchPatchMixin, DjangoBatchPatchMutation): diff --git a/aleksis/apps/lesrooster/schema/validity_range.py b/aleksis/apps/lesrooster/schema/validity_range.py index 040fc277..a3238585 100644 --- a/aleksis/apps/lesrooster/schema/validity_range.py +++ b/aleksis/apps/lesrooster/schema/validity_range.py @@ -1,14 +1,13 @@ import graphene from graphene_django.types import DjangoObjectType from graphene_django_cud.mutations import ( + DjangoBatchCreateMutation, DjangoBatchDeleteMutation, DjangoBatchPatchMutation, - DjangoCreateMutation, ) from guardian.shortcuts import get_objects_for_user from aleksis.core.schema.base import ( - DeleteMutation, DjangoFilterMixin, PermissionBatchDeleteMixin, PermissionBatchPatchMixin, @@ -40,7 +39,7 @@ class ValidityRangeType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp return queryset -class ValidityRangeCreateMutation(DjangoCreateMutation): +class ValidityRangeBatchCreateMutation(DjangoBatchCreateMutation): class Meta: model = ValidityRange permissions = ("lesrooster.create_validity_range_rule",) @@ -56,11 +55,6 @@ class ValidityRangeCreateMutation(DjangoCreateMutation): field_types = {"status": graphene.String()} -class ValidityRangeDeleteMutation(DeleteMutation): - klass = ValidityRange - permission_required = "lesrooster.delete_validityrange_rule" - - class ValidityRangeBatchDeleteMutation(PermissionBatchDeleteMixin, DjangoBatchDeleteMutation): class Meta: model = ValidityRange diff --git a/pyproject.toml b/pyproject.toml index 5266c94c..48885bcb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ url = "https://edugit.org/api/v4/projects/461/packages/pypi/simple" priority = "supplemental" [tool.poetry.dependencies] python = "^3.10" -AlekSIS-Core = "^4.0.0.dev2" +AlekSIS-Core = "^4.0.0.dev3" AlekSIS-App-Chronos = "^4.0.0.dev1" AlekSIS-App-Cursus = "^0.1.dev0" django-recurrence = "^1.11.1" -- GitLab From 3f3e1918a9f10fdfa645a29d205206b84f6bf0fe Mon Sep 17 00:00:00 2001 From: magicfelix <felix@felix-zauberer.de> Date: Thu, 15 Feb 2024 21:00:22 +0100 Subject: [PATCH 02/17] Hide period field for break slots --- .../frontend/components/lesson_raster/SlotCreator.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCreator.vue b/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCreator.vue index bbf5d06b..f567120e 100644 --- a/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCreator.vue +++ b/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCreator.vue @@ -126,7 +126,7 @@ export default defineComponent({ </template> <template #content> - <div aria-required="true"> + <div v-if="!breaks" aria-required="true"> <positive-small-integer-field v-model="slots.period" :label="$t('lesrooster.slot.period')" -- GitLab From 56feacf1238a9892c3cf966f195c929f53b6498c Mon Sep 17 00:00:00 2001 From: Michael Bauer <michael-bauer@posteo.de> Date: Fri, 16 Feb 2024 13:03:46 +0100 Subject: [PATCH 03/17] Fix LessonRaster --- .../frontend/components/lesson_raster/LessonRaster.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue b/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue index bc50cbe0..989d5f49 100644 --- a/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue +++ b/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue @@ -171,15 +171,15 @@ :disabled=" $apollo.queries.items.loading || loading.main || loading[slot.weekday] " - @click:delete="deleteSingularSlot" + @click:delete="deleteSlot" @click:copy="copySingularSlotTodDay($event.item, $event.weekday)" :weekdays="weekdays" :id="'#slot-' + slot.id" /> <delete-dialog - :gql-mutation="deleteMutation" - :gql-query="$apollo.queries.items" + :gql-delete-mutation="deleteMutation" + :affected-query="$apollo.queries.items" :items="itemsToDelete" v-model="deleteDialog" > @@ -405,7 +405,7 @@ export default { }); }, deleteSlot(slot) { - this.itemToDeletes = [slot] + this.itemsToDelete = [slot] this.deleteDialog = true; }, deleteSlotsOfDay(weekday) { -- GitLab From daf781e5cce5df62e24554f12fd27965ae70d5d7 Mon Sep 17 00:00:00 2001 From: Michael Bauer <michael-bauer@posteo.de> Date: Fri, 16 Feb 2024 13:21:51 +0100 Subject: [PATCH 04/17] Fix TimeBoundCourseConfig --- .../timebound_course_config/TimeboundCourseConfigCRUDTable.vue | 2 +- .../timebound_course_config/timeboundCourseConfig.graphql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue index 814b3258..dfac53ef 100644 --- a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue +++ b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue @@ -207,7 +207,7 @@ export default { validityRange: item.validityRange?.id, lessonQuota: item.lessonQuota, }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); + return Object.fromEntries(Object.entries(item).filter(([key, value]) => !(value === undefined))); }, }, apollo: { diff --git a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql index 044a2be2..6b1e3b0a 100644 --- a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql +++ b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql @@ -80,7 +80,7 @@ mutation deleteTimeboundCourseConfigs($ids: [ID]!) { mutation updateTimeboundCourseConfigs( $input: [BatchPatchTimeboundCourseConfigInput]! ) { - batchMutation: updateTimeboundCourseConfigs(input: $input) { + updateTimeboundCourseConfigs(input: $input) { items: timeboundCourseConfigs { ...timeboundCourseConfigFields course { -- GitLab From 0c3f7e4977534754c6553f5a1d474a82c7b2d601 Mon Sep 17 00:00:00 2001 From: magicfelix <felix@felix-zauberer.de> Date: Fri, 16 Feb 2024 20:05:57 +0100 Subject: [PATCH 05/17] Fix things related to new CRUD lists and mutations --- .../components/breaks_and_slots/Break.vue | 4 +- .../breaks_and_slots/LesroosterSlot.vue | 5 +- .../components/breaks_and_slots/break.graphql | 2 +- .../components/breaks_and_slots/slot.graphql | 2 +- .../components/supervision/Supervision.vue | 6 +- .../supervision/supervision.graphql | 2 +- .../TimeboundCourseConfigCRUDTable.vue | 2 +- .../timeboundCourseConfig.graphql | 2 +- .../TimetableManagement.vue | 84 ++++++++++--------- .../timetableManagement.graphql | 10 +-- .../validity_range/TimeGridField.vue | 8 +- .../validity_range/ValidityRange.vue | 10 +-- .../validity_range/ValidityRangeField.vue | 2 +- .../validity_range/validityRange.graphql | 14 ++-- 14 files changed, 81 insertions(+), 72 deletions(-) diff --git a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue index 52bf8e28..4ece76f3 100644 --- a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue +++ b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue @@ -56,13 +56,13 @@ export default { item = { id: item.id, name: item.name, - weekday: this.weekdayAsInt(item.weekday), + weekday: item.weekday ? this.weekdayAsInt(item.weekday) : undefined, period: null, timeStart: item.timeStart, timeEnd: item.timeEnd, timeGrid: item.timeGrid?.id, }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); }, }, }; diff --git a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue index cb6f55cb..833ee1d3 100644 --- a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue +++ b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue @@ -192,13 +192,14 @@ export default { item = { id: item.id, name: item.name, - weekday: this.weekdayAsInt(item.weekday), + weekday: item.weekday ? this.weekdayAsInt(item.weekday) : undefined, period: item.period, timeStart: item.timeStart, timeEnd: item.timeEnd, timeGrid: item.timeGrid?.id, }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); + console.trace(item); + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); }, formatTimeGrid(item) { if (!item) return null; diff --git a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/break.graphql b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/break.graphql index 8a764a73..324d35b3 100644 --- a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/break.graphql +++ b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/break.graphql @@ -58,7 +58,7 @@ mutation deleteBreakSlots($ids: [ID]!) { } mutation updateBreakSlots($input: [BatchPatchBreakSlotInput]!) { - batchMutation: updateBreakSlots(input: $input) { + updateBreakSlots(input: $input) { items: breakSlots { id name diff --git a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/slot.graphql b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/slot.graphql index 3c6b2362..f9b8f08e 100644 --- a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/slot.graphql +++ b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/slot.graphql @@ -57,7 +57,7 @@ mutation deleteSlots($ids: [ID]!) { } mutation updateSlots($input: [BatchPatchSlotInput]!) { - batchMutation: updateSlots(input: $input) { + updateSlots(input: $input) { items: slots { id name diff --git a/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue b/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue index 200e0150..e4825810 100644 --- a/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue +++ b/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue @@ -159,7 +159,7 @@ import { rooms } from "aleksis.core/components/room/room.graphql"; import { breakSlots } from "../breaks_and_slots/break.graphql"; import { subjects, - createSubject, + createSubjects, } from "aleksis.apps.cursus/components/subject.graphql"; import { RRule } from "rrule"; @@ -199,7 +199,7 @@ export default { }, subject: { gqlQuery: subjects, - gqlCreateMutation: createSubject, + gqlCreateMutation: createSubjects, transformCreateData(item) { return { ...item, parent: item.parent?.id }; }, @@ -304,7 +304,7 @@ export default { subject: item.subject?.id, recurrence: this.getRRule(item.breakSlot.timeGrid).toString(), }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); }, }, }; diff --git a/aleksis/apps/lesrooster/frontend/components/supervision/supervision.graphql b/aleksis/apps/lesrooster/frontend/components/supervision/supervision.graphql index c37ad32d..12cda730 100644 --- a/aleksis/apps/lesrooster/frontend/components/supervision/supervision.graphql +++ b/aleksis/apps/lesrooster/frontend/components/supervision/supervision.graphql @@ -62,7 +62,7 @@ mutation deleteSupervisions($ids: [ID]!) { } mutation updateSupervisions($input: [BatchPatchSupervisionInput]!) { - batchMutation: updateSupervisions(input: $input) { + updateSupervisions(input: $input) { items: supervisions { ...supervisionFields } diff --git a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue index dfac53ef..048f37c0 100644 --- a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue +++ b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue @@ -207,7 +207,7 @@ export default { validityRange: item.validityRange?.id, lessonQuota: item.lessonQuota, }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => !(value === undefined))); + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); }, }, apollo: { diff --git a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql index 6b1e3b0a..885c6d33 100644 --- a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql +++ b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/timeboundCourseConfig.graphql @@ -73,7 +73,7 @@ mutation createTimeboundCourseConfigs( mutation deleteTimeboundCourseConfigs($ids: [ID]!) { deleteTimeboundCourseConfigs(ids: $ids) { - ok + deletionCount } } diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue index 92283488..cde02b2b 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue @@ -2,13 +2,13 @@ import { defineComponent } from "vue"; import { courses, - createLesson, - deleteLesson, + createLessons, + deleteLessons, gqlGroups, lessonObjects, moveLesson, overlayLessons, - updateLesson, + updateLessons, } from "./timetableManagement.graphql"; import { gqlTeachers } from "../helper.graphql"; import { timeGrids } from "../validity_range/validityRange.graphql"; @@ -56,9 +56,9 @@ export default defineComponent({ courseSearch: null, lessonsUsed: {}, lessonQuotaTotal: 0, - deleteMutation: deleteLesson, + deleteMutation: deleteLessons, deleteDialog: false, - itemToDelete: null, + itemsToDelete: [], selectedObject: null, selectedObjectType: null, selectedObjectTitle: "", @@ -90,7 +90,7 @@ export default defineComponent({ value: "rooms", }, ], - mutation: updateLesson, + mutation: updateLessons, }, draggedItem: null, overlayLessons: [], @@ -385,15 +385,15 @@ export default defineComponent({ .mutate({ mutation: moveLesson, variables: { - id: eventData.data.id, input: { + id: eventData.data.id, slotStart: newStartSlotId, slotEnd: newEndSlotId, }, }, optimisticResponse: { - updateLesson: { - lesson: { + updateLessons: { + lessons: { ...eventData.data, slotStart: newStartSlot, slotEnd: newEndSlot, @@ -406,7 +406,7 @@ export default defineComponent({ store, { data: { - updateLesson: { lesson }, + updateLessons: { lessons }, }, }, ) { @@ -424,14 +424,16 @@ export default defineComponent({ return; } - const index = storedData.lessonObjects.findIndex( - (lessonObject) => lessonObject.id === lesson.id, - ); - storedData.lessonObjects[index].slotStart = lesson.slotStart; - storedData.lessonObjects[index].slotEnd = lesson.slotEnd; + lessons.forEach((lesson) => { + const index = storedData.lessonObjects.findIndex( + (lessonObject) => lessonObject.id === lesson.id, + ); + storedData.lessonObjects[index].slotStart = lesson.slotStart; + storedData.lessonObjects[index].slotEnd = lesson.slotEnd; - // Write data back to the cache - store.writeQuery({ ...query, data: storedData }); + // Write data back to the cache + store.writeQuery({ ...query, data: storedData }); + }); }, }) .then(() => { @@ -454,7 +456,7 @@ export default defineComponent({ const recurrenceString = rule.toString(); this.$apollo .mutate({ - mutation: createLesson, + mutation: createLessons, variables: { input: { slotStart: newStartSlotId, @@ -468,8 +470,8 @@ export default defineComponent({ }, }, optimisticResponse: { - createLesson: { - lesson: { + createLessons: { + lessons: { id: "temporary-lesson-id-" + crypto.randomUUID(), slotStart: newStartSlot, slotEnd: newEndSlot, @@ -491,7 +493,7 @@ export default defineComponent({ store, { data: { - createLesson: { lesson }, + createLessons: { lessons }, }, }, ) { @@ -509,7 +511,7 @@ export default defineComponent({ return; } - storedData.lessonObjects.push(lesson); + storedData.lessonObjects.concat(lessons); // Write data back to the cache store.writeQuery({ ...query, data: storedData }); @@ -558,15 +560,15 @@ export default defineComponent({ .mutate({ mutation: moveLesson, variables: { - id: lesson.id, input: { + id: lesson.id, slotStart: slotStart.id, slotEnd: slotEnd.id, }, }, optimisticResponse: { - updateLesson: { - lesson: { + updateLessons: { + lessons: { ...lesson, slotStart: slotStart, slotEnd: slotEnd, @@ -579,7 +581,7 @@ export default defineComponent({ store, { data: { - updateLesson: { lesson }, + updateLessons: { lessons }, }, }, ) { @@ -597,14 +599,16 @@ export default defineComponent({ return; } - const index = storedData.lessonObjects.findIndex( - (lessonObject) => lessonObject.id === lesson.id, - ); - storedData.lessonObjects[index].slotStart = lesson.slotStart; - storedData.lessonObjects[index].slotEnd = lesson.slotEnd; + lessons.forEach((lesson) => { + const index = storedData.lessonObjects.findIndex( + (lessonObject) => lessonObject.id === lesson.id, + ); + storedData.lessonObjects[index].slotStart = lesson.slotStart; + storedData.lessonObjects[index].slotEnd = lesson.slotEnd; - // Write data back to the cache - store.writeQuery({ ...query, data: storedData }); + // Write data back to the cache + store.writeQuery({ ...query, data: storedData }); + }); }, }) .then(() => { @@ -647,7 +651,7 @@ export default defineComponent({ this.changeLessonSlots(lesson, lesson.slotStart, slotEnd); }, deleteLesson(lesson) { - this.itemToDelete = lesson; + this.itemsToDelete = [lesson]; this.deleteDialog = true; }, teacherClick(teacher) { @@ -1083,13 +1087,17 @@ export default defineComponent({ </mobile-fullscreen-dialog> <delete-dialog - :gql-mutation="deleteMutation" - :gql-query="$apollo.queries.lessonObjects" + :gql-delete-mutation="deleteMutation" + :affected-query="$apollo.queries.lessonObjects" v-model="deleteDialog" - :item="itemToDelete" + :items="itemsToDelete" > <template #body> - {{ itemToDelete.subject?.name || itemToDelete.course.subject.name }} + <ul class="text-body-1"> + <li v-for="item in itemsToDelete" :key="'delete-' + item.id"> + {{ item.subject?.name || item.course.subject.name }} + </li> + </ul> </template> </delete-dialog> diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql b/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql index 3c6a73a6..8f29aa75 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql @@ -198,9 +198,9 @@ mutation createLessons($input: [BatchCreateLessonInput]!) { } } -mutation moveLesson($id: ID!, $input: PatchLessonInput!) { - updateLesson(id: $id, input: $input) { - lesson { +mutation moveLesson($input: [BatchPatchLessonInput]!) { + updateLessons(input: $input) { + lessons { id slotStart { id @@ -245,8 +245,8 @@ mutation updateLessons($input: [BatchPatchLessonInput]!) { } } -mutation deleteLesson($ids: [ID]!) { +mutation deleteLessons($ids: [ID]!) { deleteLessons(ids: $ids) { - ok + deletionCount } } diff --git a/aleksis/apps/lesrooster/frontend/components/validity_range/TimeGridField.vue b/aleksis/apps/lesrooster/frontend/components/validity_range/TimeGridField.vue index 03352820..69246ca8 100644 --- a/aleksis/apps/lesrooster/frontend/components/validity_range/TimeGridField.vue +++ b/aleksis/apps/lesrooster/frontend/components/validity_range/TimeGridField.vue @@ -5,7 +5,7 @@ import ValidityRangeField from "./ValidityRangeField.vue"; <script> import { defineComponent } from "vue"; -import { timeGrids, createTimeGrid } from "./validityRange.graphql"; +import { timeGrids, createTimeGrids } from "./validityRange.graphql"; import { gqlGroups } from "../helper.graphql"; export default defineComponent({ @@ -38,7 +38,7 @@ export default defineComponent({ ], i18nKey: "lesrooster.validity_range.time_grid", gqlQuery: timeGrids, - gqlCreateMutation: createTimeGrid, + gqlCreateMutation: createTimeGrids, defaultItem: { isGeneric: false, group: null, @@ -63,7 +63,7 @@ export default defineComponent({ (group) => !this.$refs.field.items.some( (timeGrid) => - timeGrid.validityRange.id === itemModel.validityRange.id && + timeGrid.validityRange.id === itemModel.validityRange?.id && timeGrid.group !== null && timeGrid.group.id === group.id, ), @@ -75,7 +75,7 @@ export default defineComponent({ // Is there a timeGrid that has the same validityRange as we and no group? return this.$refs.field.items.some( (timeGrid) => - timeGrid.validityRange.id === itemModel.validityRange.id && + timeGrid.validityRange.id === itemModel.validityRange?.id && timeGrid.group === null, ); }, diff --git a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue index 1dbf398e..a5f0b326 100644 --- a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue +++ b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue @@ -212,8 +212,8 @@ import { createValidityRanges, deleteValidityRanges, updateValidityRanges, - createTimeGrid, - deleteTimeGrid, + createTimeGrids, + deleteTimeGrids, } from "./validityRange.graphql"; import { gqlGroups } from "../helper.graphql"; @@ -265,13 +265,13 @@ export default { open: false, deleteOpen: false, deleteItem: null, - deleteMutation: deleteTimeGrid, + deleteMutation: deleteTimeGrids, range: null, object: { isGeneric: false, group: null, }, - mutation: createTimeGrid, + mutation: createTimeGrids, fields: [ { text: this.$t( @@ -324,7 +324,7 @@ export default { schoolTerm: item.schoolTerm?.id, status: item.status?.toLowerCase(), }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); }, createTimeGridFor(validityRange) { this.timeGrids.range = validityRange; diff --git a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue index c1aaa47a..da6cfcb4 100644 --- a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue +++ b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue @@ -110,7 +110,7 @@ export default { dateEnd: item.dateEnd, schoolTerm: item.schoolTerm.id, }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value === undefined)); + return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); }, }, }; diff --git a/aleksis/apps/lesrooster/frontend/components/validity_range/validityRange.graphql b/aleksis/apps/lesrooster/frontend/components/validity_range/validityRange.graphql index d698ab15..7124e149 100644 --- a/aleksis/apps/lesrooster/frontend/components/validity_range/validityRange.graphql +++ b/aleksis/apps/lesrooster/frontend/components/validity_range/validityRange.graphql @@ -55,7 +55,7 @@ mutation deleteValidityRanges($ids: [ID]!) { } mutation updateValidityRanges($input: [BatchPatchValidityRangeInput]!) { - batchMutation: updateValidityRanges(input: $input) { + utation: updateValidityRanges(input: $input) { items: validityRanges { id name @@ -89,9 +89,9 @@ query currentValidityRange { } } -mutation createTimeGrid($input: CreateTimeGridInput!) { - createTimeGrid(input: $input) { - item: timeGrid { +mutation createTimeGrids($input: [BatchCreateTimeGridInput]!) { + createTimeGrids(input: $input) { + items: timeGrids { id group { id @@ -105,9 +105,9 @@ mutation createTimeGrid($input: CreateTimeGridInput!) { } } -mutation deleteTimeGrid($id: ID!) { - deleteTimeGrid(id: $id) { - ok +mutation deleteTimeGrids($ids: [ID]!) { + deleteTimeGrids(id: $ids) { + deletionCount } } -- GitLab From 9c9a8c6ec389d3c89af4be15e3c402f8a80639b2 Mon Sep 17 00:00:00 2001 From: Hangzhi Yu <hangzhi@protonmail.com> Date: Sat, 17 Feb 2024 14:21:39 +0100 Subject: [PATCH 06/17] Fix permission check in timebound course config field in subjects query --- aleksis/apps/lesrooster/schema/timebound_course_config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aleksis/apps/lesrooster/schema/timebound_course_config.py b/aleksis/apps/lesrooster/schema/timebound_course_config.py index 705f08ec..b0c1feaa 100644 --- a/aleksis/apps/lesrooster/schema/timebound_course_config.py +++ b/aleksis/apps/lesrooster/schema/timebound_course_config.py @@ -70,12 +70,13 @@ class LesroosterExtendedCourseType(CourseType): @staticmethod def resolve_lr_timebound_course_configs(root, info, **kwargs): - if not info.context.user.has_perm("lesrostter.view_timeboundcourseconfig_rule"): + if not info.context.user.has_perm("lesrooster.view_timeboundcourseconfig_rule"): return get_objects_for_user( info.context.user, "lesrooster.view_timeboundcourseconfig", root.lr_timebound_course_configs.all(), ) + return root.lr_timebound_course_configs.all() class LesroosterExtendedSubjectType(SubjectType): -- GitLab From 312a8d718b76c7b32e8cd4b4e0b1a83f51c384b0 Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Sat, 17 Feb 2024 21:47:52 +0100 Subject: [PATCH 07/17] Implement the changes of using batch mutations in optimistic response (previously forgotten) --- .../TimetableManagement.vue | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue index cde02b2b..7d641c59 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue @@ -393,13 +393,13 @@ export default defineComponent({ }, optimisticResponse: { updateLessons: { - lessons: { + lessons: [{ ...eventData.data, slotStart: newStartSlot, slotEnd: newEndSlot, isOptimistic: true, - }, - __typename: "LessonPatchMutation", + }], + __typename: "LessonBatchPatchMutation", }, }, update( @@ -471,7 +471,7 @@ export default defineComponent({ }, optimisticResponse: { createLessons: { - lessons: { + items: [{ id: "temporary-lesson-id-" + crypto.randomUUID(), slotStart: newStartSlot, slotEnd: newEndSlot, @@ -485,15 +485,15 @@ export default defineComponent({ canDelete: true, recurrence: recurrenceString, __typename: "LessonType", - }, - __typename: "LessonCreateMutation", + }], + __typename: "LessonBatchCreateMutation", }, }, update( store, { data: { - createLessons: { lessons }, + createLessons: { items }, }, }, ) { @@ -511,7 +511,7 @@ export default defineComponent({ return; } - storedData.lessonObjects.concat(lessons); + items.forEach(lesson => storedData.lessonObjects.push(lesson)); // Write data back to the cache store.writeQuery({ ...query, data: storedData }); @@ -568,13 +568,13 @@ export default defineComponent({ }, optimisticResponse: { updateLessons: { - lessons: { + lessons: [{ ...lesson, slotStart: slotStart, slotEnd: slotEnd, isOptimistic: true, - }, - __typename: "LessonPatchMutation", + }], + __typename: "LessonBatchPatchMutation", }, }, update( -- GitLab From 8d15a7ca00ce2b7e95dba2f69b1b2089173e9057 Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Sat, 17 Feb 2024 21:48:19 +0100 Subject: [PATCH 08/17] Fix vue errors regarding keys of rooms --- .../timetable_management/TimetableOverlayCard.vue | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableOverlayCard.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableOverlayCard.vue index 8d05ecb6..92de1150 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableOverlayCard.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableOverlayCard.vue @@ -45,9 +45,10 @@ export default { ); }, rooms() { - return this.lesson.rooms.filter( + // dragged item may be a course which doesn't have a field rooms + return this.lesson.rooms?.filter( (lessonRoom) => - !!this.draggedItem.rooms.find((room) => room.id === lessonRoom.id), + !!this.draggedItem.rooms?.find((room) => room.id === lessonRoom.id), ); }, teachers() { @@ -68,7 +69,7 @@ export default { v-for="room in rooms" icon="mdi-home-off-outline" color="warning" - :key="room.id" + :key="'room-' + room.id" > <colored-short-name-chip class="short" :item="room" :elevation="0" /> </blocking-card> @@ -76,7 +77,7 @@ export default { v-for="teacher in teachers" icon="mdi-account-off-outline" color="warning" - :key="teacher.id" + :key="'teacher-' + teacher.id" > <colored-short-name-chip class="short" :item="teacher" :elevation="0" /> </blocking-card> -- GitLab From 919915ba47323aa080fa53c69ae5abd2b624524a Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Sun, 18 Feb 2024 19:46:35 +0100 Subject: [PATCH 09/17] Stop miniplans from not showing up due to duplicate keys --- .../components/timetable_management/TimetableManagement.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue index 7d641c59..5230d19e 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue @@ -64,6 +64,7 @@ export default defineComponent({ selectedObjectTitle: "", selectedObjectDialogOpen: false, selectedObjectDialogTab: null, + timeGrids: [], groups: [], selectedGroup: null, lessonEdit: { @@ -1067,7 +1068,7 @@ export default defineComponent({ </v-card-title> <v-card-text> <v-tabs-items v-model="selectedObjectDialogTab"> - <v-tab-item v-for="timeGrid in timeGrids" :key="timeGrid.id"> + <v-tab-item v-for="timeGrid in timeGrids" :key="'tabItem-' + timeGrid.id"> <teacher-time-table v-if="internalTimeGrid && selectedObjectType === 'teacher'" :teacher-id="selectedObject" -- GitLab From 44e0fed71cc0e49093c01de1f239d441085ea2b3 Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Sun, 18 Feb 2024 19:47:08 +0100 Subject: [PATCH 10/17] Make Timetable creation fullwidth --- aleksis/apps/lesrooster/frontend/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aleksis/apps/lesrooster/frontend/index.js b/aleksis/apps/lesrooster/frontend/index.js index 1a82aec7..5f072d56 100644 --- a/aleksis/apps/lesrooster/frontend/index.js +++ b/aleksis/apps/lesrooster/frontend/index.js @@ -58,6 +58,7 @@ export default { toolbarTitle: "lesrooster.timetable_management.menu_title", icon: "mdi-magnet", permission: "lesrooster.plan_timetables_rule", + fullWidth: true, }, children: [ { @@ -67,7 +68,10 @@ export default { name: "lesrooster.timetable_management", props: true, meta: { + titleKey: "lesrooster.timetable_management.menu_title", + toolbarTitle: "lesrooster.timetable_management.menu_title", permission: "lesrooster.plan_timetables_rule", + fullWidth: true, }, }, ], -- GitLab From a06aebafd56dd28f62e018d550296e9b0cf80101 Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Tue, 20 Feb 2024 11:43:31 +0100 Subject: [PATCH 11/17] Auto-select first tab --- .../components/timetable_management/TimetableManagement.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue index 5230d19e..9e3f70f1 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue @@ -63,7 +63,7 @@ export default defineComponent({ selectedObjectType: null, selectedObjectTitle: "", selectedObjectDialogOpen: false, - selectedObjectDialogTab: null, + selectedObjectDialogTab: 0, timeGrids: [], groups: [], selectedGroup: null, -- GitLab From e36b16fb19e60114a8185794999fa955e1836ca4 Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Tue, 20 Feb 2024 11:43:49 +0100 Subject: [PATCH 12/17] Make all iteration keys unique --- .../components/timetable_management/TimetableManagement.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue index 9e3f70f1..536ed145 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue @@ -872,7 +872,7 @@ export default defineComponent({ <div id="periods"> <period-card v-for="(period, index) in periods" - :key="period" + :key="'period-' + period" :period="period" :weekdays="weekdays" :time-ranges=" @@ -974,7 +974,7 @@ export default defineComponent({ :periods="periods" :weekdays="weekdays" :lesson="overlayLesson" - :key="overlayLesson.id" + :key="'overlay-' + overlayLesson.id" /> </template> </drag-grid> @@ -1061,7 +1061,7 @@ export default defineComponent({ v-if="timeGrids && timeGrids.length > 1" class="width-max-content" > - <v-tab v-for="timeGrid in timeGrids" :key="timeGrid.id"> + <v-tab v-for="timeGrid in timeGrids" :key="'tabSelector-' + timeGrid.id"> {{ formatTimeGrid(timeGrid) }} </v-tab> </v-tabs> -- GitLab From 8931e0b678584520a8fe1c36570658bd74ce4266 Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Tue, 20 Feb 2024 11:52:02 +0100 Subject: [PATCH 13/17] Prevent duplicate entries in miniplans and overlays --- aleksis/apps/lesrooster/schema/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aleksis/apps/lesrooster/schema/__init__.py b/aleksis/apps/lesrooster/schema/__init__.py index a5912290..44c4167a 100644 --- a/aleksis/apps/lesrooster/schema/__init__.py +++ b/aleksis/apps/lesrooster/schema/__init__.py @@ -225,7 +225,7 @@ class Query(graphene.ObjectType): Q(teachers=teacher) | Q(course__teachers=teacher), slot_start__time_grid_id=time_grid, slot_end__time_grid_id=time_grid, - ) + ).distinct() @staticmethod def resolve_lesson_objects_for_room(root, info, room, time_grid): @@ -236,7 +236,7 @@ class Query(graphene.ObjectType): rooms=room, slot_start__time_grid_id=time_grid, slot_end__time_grid_id=time_grid, - ) + ).distinct() @staticmethod def resolve_lessons_objects_for_rooms_or_teachers( @@ -253,7 +253,7 @@ class Query(graphene.ObjectType): Q(rooms__in=rooms) | Q(teachers__in=teachers) | Q(course__teachers__in=teachers), slot_start__time_grid_id=time_grid, slot_end__time_grid_id=time_grid, - ) + ).distinct() @staticmethod def resolve_groups_by_time_grid(root, info, time_grid=None, **kwargs): -- GitLab From 71fbf4e0dfde7e810b021b92b67bbb59602e848f Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Fri, 23 Feb 2024 16:53:43 +0100 Subject: [PATCH 14/17] Send ID when editing lesson --- .../components/timetable_management/TimetableManagement.vue | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue index 536ed145..3d808708 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue @@ -710,6 +710,11 @@ export default defineComponent({ const index = storedData.lessonObjects.findIndex( (lessonObject) => lessonObject.id === lesson.id, ); + + if (index === -1) { + return; + } + storedData.lessonObjects[index].subject = lesson.subject; storedData.lessonObjects[index].teachers = lesson.teachers; storedData.lessonObjects[index].rooms = lesson.rooms; @@ -729,6 +734,7 @@ export default defineComponent({ }, lessonEditGetPatchData(lesson) { return { + id: lesson.id, subject: lesson.subject.id, teachers: lesson.teachers.map((teacher) => teacher.id), rooms: lesson.rooms.map((room) => room.id), -- GitLab From 186edb338023767627762bd0e9b3a7cc492cc911 Mon Sep 17 00:00:00 2001 From: Julian Leucker <leuckerj@gmail.com> Date: Fri, 23 Feb 2024 16:58:08 +0100 Subject: [PATCH 15/17] Skip queries until group is loaded fully --- .../components/timetable_management/TimetableManagement.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue index 3d808708..443b5b53 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue @@ -234,7 +234,8 @@ export default defineComponent({ }, computed: { readyForQueries() { - return this.internalTimeGrid !== null && this.selectedGroup !== null; + // Non-typesafe check to also handle undefined + return this.internalTimeGrid != null && this.selectedGroup != null && this.selectedGroup.id != null; }, lessons() { return this.lessonObjects -- GitLab From dc21fc185ea320b665d6b5699687cfe65a73ac36 Mon Sep 17 00:00:00 2001 From: Jonathan Weth <git@jonathanweth.de> Date: Sat, 24 Feb 2024 12:47:42 +0100 Subject: [PATCH 16/17] Bump version of AlekSIS-Core --- pyproject.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 48885bcb..b451c0d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "AlekSIS-App-Lesrooster" -version = "0.1" +version = "0.1.0.dev0" packages = [ { include = "aleksis" } ] @@ -32,9 +32,10 @@ priority = "primary" name = "gitlab" url = "https://edugit.org/api/v4/projects/461/packages/pypi/simple" priority = "supplemental" + [tool.poetry.dependencies] python = "^3.10" -AlekSIS-Core = "^4.0.0.dev3" +AlekSIS-Core = "^4.0.0.dev4" AlekSIS-App-Chronos = "^4.0.0.dev1" AlekSIS-App-Cursus = "^0.1.dev0" django-recurrence = "^1.11.1" -- GitLab From 18364fba6f5554ea52b5f4248a7ace73aa827320 Mon Sep 17 00:00:00 2001 From: Jonathan Weth <git@jonathanweth.de> Date: Sat, 24 Feb 2024 14:27:19 +0100 Subject: [PATCH 17/17] Reformat --- .../components/breaks_and_slots/Break.vue | 4 +- .../breaks_and_slots/LesroosterSlot.vue | 13 ++-- .../components/lesson_raster/LessonRaster.vue | 2 +- .../components/supervision/Supervision.vue | 4 +- .../TimeboundCourseConfigCRUDTable.vue | 4 +- .../TimetableManagement.vue | 78 +++++++++++-------- .../validity_range/ValidityRange.vue | 4 +- .../validity_range/ValidityRangeField.vue | 4 +- aleksis/apps/lesrooster/schema/__init__.py | 1 - aleksis/apps/lesrooster/schema/lesson.py | 1 - 10 files changed, 68 insertions(+), 47 deletions(-) diff --git a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue index 4ece76f3..8c39f208 100644 --- a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue +++ b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/Break.vue @@ -62,7 +62,9 @@ export default { timeEnd: item.timeEnd, timeGrid: item.timeGrid?.id, }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); + return Object.fromEntries( + Object.entries(item).filter(([key, value]) => value !== undefined), + ); }, }, }; diff --git a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue index 833ee1d3..83da9f69 100644 --- a/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue +++ b/aleksis/apps/lesrooster/frontend/components/breaks_and_slots/LesroosterSlot.vue @@ -113,12 +113,7 @@ import TimeGridField from "../validity_range/TimeGridField.vue"; </template> <script> -import { - slots, - createSlots, - deleteSlots, - updateSlots, -} from "./slot.graphql"; +import { slots, createSlots, deleteSlots, updateSlots } from "./slot.graphql"; export default { name: "LesroosterSlot", @@ -198,8 +193,10 @@ export default { timeEnd: item.timeEnd, timeGrid: item.timeGrid?.id, }; - console.trace(item); - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); + console.trace(item); + return Object.fromEntries( + Object.entries(item).filter(([key, value]) => value !== undefined), + ); }, formatTimeGrid(item) { if (!item) return null; diff --git a/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue b/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue index 989d5f49..bc0205fe 100644 --- a/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue +++ b/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue @@ -405,7 +405,7 @@ export default { }); }, deleteSlot(slot) { - this.itemsToDelete = [slot] + this.itemsToDelete = [slot]; this.deleteDialog = true; }, deleteSlotsOfDay(weekday) { diff --git a/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue b/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue index e4825810..2a25319d 100644 --- a/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue +++ b/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue @@ -304,7 +304,9 @@ export default { subject: item.subject?.id, recurrence: this.getRRule(item.breakSlot.timeGrid).toString(), }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); + return Object.fromEntries( + Object.entries(item).filter(([key, value]) => value !== undefined), + ); }, }, }; diff --git a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue index 048f37c0..927935ec 100644 --- a/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue +++ b/aleksis/apps/lesrooster/frontend/components/timebound_course_config/TimeboundCourseConfigCRUDTable.vue @@ -207,7 +207,9 @@ export default { validityRange: item.validityRange?.id, lessonQuota: item.lessonQuota, }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); + return Object.fromEntries( + Object.entries(item).filter(([key, value]) => value !== undefined), + ); }, }, apollo: { diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue index 443b5b53..1fbc0d46 100644 --- a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue +++ b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue @@ -235,7 +235,11 @@ export default defineComponent({ computed: { readyForQueries() { // Non-typesafe check to also handle undefined - return this.internalTimeGrid != null && this.selectedGroup != null && this.selectedGroup.id != null; + return ( + this.internalTimeGrid != null && + this.selectedGroup != null && + this.selectedGroup.id != null + ); }, lessons() { return this.lessonObjects @@ -395,12 +399,14 @@ export default defineComponent({ }, optimisticResponse: { updateLessons: { - lessons: [{ - ...eventData.data, - slotStart: newStartSlot, - slotEnd: newEndSlot, - isOptimistic: true, - }], + lessons: [ + { + ...eventData.data, + slotStart: newStartSlot, + slotEnd: newEndSlot, + isOptimistic: true, + }, + ], __typename: "LessonBatchPatchMutation", }, }, @@ -473,21 +479,23 @@ export default defineComponent({ }, optimisticResponse: { createLessons: { - items: [{ - id: "temporary-lesson-id-" + crypto.randomUUID(), - slotStart: newStartSlot, - slotEnd: newEndSlot, - subject: eventData.data.subject, - teachers: eventData.data.teachers, - // rooms: eventData.data.rooms, - rooms: [], - course: eventData.data, - isOptimistic: true, - canEdit: true, - canDelete: true, - recurrence: recurrenceString, - __typename: "LessonType", - }], + items: [ + { + id: "temporary-lesson-id-" + crypto.randomUUID(), + slotStart: newStartSlot, + slotEnd: newEndSlot, + subject: eventData.data.subject, + teachers: eventData.data.teachers, + // rooms: eventData.data.rooms, + rooms: [], + course: eventData.data, + isOptimistic: true, + canEdit: true, + canDelete: true, + recurrence: recurrenceString, + __typename: "LessonType", + }, + ], __typename: "LessonBatchCreateMutation", }, }, @@ -513,7 +521,7 @@ export default defineComponent({ return; } - items.forEach(lesson => storedData.lessonObjects.push(lesson)); + items.forEach((lesson) => storedData.lessonObjects.push(lesson)); // Write data back to the cache store.writeQuery({ ...query, data: storedData }); @@ -570,12 +578,14 @@ export default defineComponent({ }, optimisticResponse: { updateLessons: { - lessons: [{ - ...lesson, - slotStart: slotStart, - slotEnd: slotEnd, - isOptimistic: true, - }], + lessons: [ + { + ...lesson, + slotStart: slotStart, + slotEnd: slotEnd, + isOptimistic: true, + }, + ], __typename: "LessonBatchPatchMutation", }, }, @@ -1068,14 +1078,20 @@ export default defineComponent({ v-if="timeGrids && timeGrids.length > 1" class="width-max-content" > - <v-tab v-for="timeGrid in timeGrids" :key="'tabSelector-' + timeGrid.id"> + <v-tab + v-for="timeGrid in timeGrids" + :key="'tabSelector-' + timeGrid.id" + > {{ formatTimeGrid(timeGrid) }} </v-tab> </v-tabs> </v-card-title> <v-card-text> <v-tabs-items v-model="selectedObjectDialogTab"> - <v-tab-item v-for="timeGrid in timeGrids" :key="'tabItem-' + timeGrid.id"> + <v-tab-item + v-for="timeGrid in timeGrids" + :key="'tabItem-' + timeGrid.id" + > <teacher-time-table v-if="internalTimeGrid && selectedObjectType === 'teacher'" :teacher-id="selectedObject" diff --git a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue index a5f0b326..52a81562 100644 --- a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue +++ b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRange.vue @@ -324,7 +324,9 @@ export default { schoolTerm: item.schoolTerm?.id, status: item.status?.toLowerCase(), }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); + return Object.fromEntries( + Object.entries(item).filter(([key, value]) => value !== undefined), + ); }, createTimeGridFor(validityRange) { this.timeGrids.range = validityRange; diff --git a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue index da6cfcb4..72ee6326 100644 --- a/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue +++ b/aleksis/apps/lesrooster/frontend/components/validity_range/ValidityRangeField.vue @@ -110,7 +110,9 @@ export default { dateEnd: item.dateEnd, schoolTerm: item.schoolTerm.id, }; - return Object.fromEntries(Object.entries(item).filter(([key, value]) => value !== undefined)); + return Object.fromEntries( + Object.entries(item).filter(([key, value]) => value !== undefined), + ); }, }, }; diff --git a/aleksis/apps/lesrooster/schema/__init__.py b/aleksis/apps/lesrooster/schema/__init__.py index 44c4167a..d27e9288 100644 --- a/aleksis/apps/lesrooster/schema/__init__.py +++ b/aleksis/apps/lesrooster/schema/__init__.py @@ -49,7 +49,6 @@ from .supervision import ( from .time_grid import ( TimeGridBatchCreateMutation, TimeGridBatchDeleteMutation, - TimeGridBatchDeleteMutation, TimeGridType, ) from .timebound_course_config import ( diff --git a/aleksis/apps/lesrooster/schema/lesson.py b/aleksis/apps/lesrooster/schema/lesson.py index e9c87c77..a3ceb68e 100644 --- a/aleksis/apps/lesrooster/schema/lesson.py +++ b/aleksis/apps/lesrooster/schema/lesson.py @@ -13,7 +13,6 @@ from aleksis.core.schema.base import ( OptimisticResponseTypeMixin, PermissionBatchDeleteMixin, PermissionBatchPatchMixin, - PermissionPatchMixin, PermissionsTypeMixin, ) -- GitLab