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 b1b6156eb677aa3d0fa98fdeb792ec5cd87a746b..8c39f2083ceb3dc41e13e871f54636e0f9c0847c 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,19 @@ 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), + weekday: item.weekday ? this.weekdayAsInt(item.weekday) : undefined, 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 19189786fc653a67acfb24f6ad7b13a19e8c42ed..83da9f69c60148f2039591e2a5f5f9fd0b629992 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" @@ -114,13 +113,7 @@ import TimeGridField from "../validity_range/TimeGridField.vue"; </template> <script> -import { - slots, - createSlot, - deleteSlot, - deleteSlots, - updateSlots, -} from "./slot.graphql"; +import { slots, createSlots, deleteSlots, updateSlots } from "./slot.graphql"; export default { name: "LesroosterSlot", @@ -156,10 +149,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 +177,26 @@ 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), + weekday: item.weekday ? this.weekdayAsInt(item.weekday) : undefined, period: item.period, timeStart: item.timeStart, timeEnd: item.timeEnd, - timeGrid: item.timeGrid.id, - })); + timeGrid: item.timeGrid?.id, + }; + 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 63c2087d1f17c516c84ef8ac8e3fd84381fccd1c..324d35b3862627fa39a2362070a2b9ca8e1cfcb2 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 @@ -90,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 269faa53c9f3bb62ea2a5d138c778279089d433f..f9b8f08e21a95e867438e1852bc6819a051d84b8 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 @@ -89,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/lesson_raster/LessonRaster.vue b/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue index 02860dc8c49c0a6a08136da9eb3749fe4e7dd50a..bc0205fe045c8ba045a7b13be511c7975158588d 100644 --- a/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue +++ b/aleksis/apps/lesrooster/frontend/components/lesson_raster/LessonRaster.vue @@ -171,37 +171,21 @@ :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" - 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" + :gql-delete-mutation="deleteMutation" + :affected-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.itemsToDelete = [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/lesson_raster/SlotCreator.vue b/aleksis/apps/lesrooster/frontend/components/lesson_raster/SlotCreator.vue index bbf5d06bea283115f809cc6658fdc701854bdd62..f567120ee7a3b57756bd56896da930d48dd287f8 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')" diff --git a/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue b/aleksis/apps/lesrooster/frontend/components/supervision/Supervision.vue index 730c1bfcca44129f2d2a4e62e785979861da49ac..2a25319dab6e75a3540aa26b9b1e94517871c2fd 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"; @@ -161,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"; @@ -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: [], @@ -202,7 +199,7 @@ export default { }, subject: { gqlQuery: subjects, - gqlCreateMutation: createSubject, + gqlCreateMutation: createSubjects, transformCreateData(item) { return { ...item, parent: item.parent?.id }; }, @@ -298,15 +295,18 @@ 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 26556dfe7a3abb474e64b04f19243df70e110770..12cda730c15f133992a90e36134e329fc210a5ca 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 @@ -76,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 bf93ef62c6150e8610ad570b437a140f483d2b7c..927935eccdde231413106c0efef0b1ba55b57fa7 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,17 @@ 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 7a0a700a9820ae1453204db37abab6f804448b7b..79715008b5a2e9c0616de9c65ebacdb46a664463 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 9ede745ed2fff96245478ed7871745a751cadf58..885c6d3349c978c90bc70f49278de5799c26dec4 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,16 +71,16 @@ mutation batchCreateTimeboundCourseConfig( } } -mutation deleteTimeboundCourseConfig($id: ID!) { - deleteTimeboundCourseConfig(id: $id) { - ok +mutation deleteTimeboundCourseConfigs($ids: [ID]!) { + deleteTimeboundCourseConfigs(ids: $ids) { + deletionCount } } mutation updateTimeboundCourseConfigs( $input: [BatchPatchTimeboundCourseConfigInput]! ) { - batchMutation: updateTimeboundCourseConfigs(input: $input) { + updateTimeboundCourseConfigs(input: $input) { items: timeboundCourseConfigs { ...timeboundCourseConfigFields course { diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableManagement.vue index 9228348857cc5006068248fe38971666a1d0bdbe..1fbc0d46d7844cf143a92476de933c30f9ff3d7b 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,14 +56,15 @@ export default defineComponent({ courseSearch: null, lessonsUsed: {}, lessonQuotaTotal: 0, - deleteMutation: deleteLesson, + deleteMutation: deleteLessons, deleteDialog: false, - itemToDelete: null, + itemsToDelete: [], selectedObject: null, selectedObjectType: null, selectedObjectTitle: "", selectedObjectDialogOpen: false, - selectedObjectDialogTab: null, + selectedObjectDialogTab: 0, + timeGrids: [], groups: [], selectedGroup: null, lessonEdit: { @@ -90,7 +91,7 @@ export default defineComponent({ value: "rooms", }, ], - mutation: updateLesson, + mutation: updateLessons, }, draggedItem: null, overlayLessons: [], @@ -233,7 +234,12 @@ 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 @@ -385,28 +391,30 @@ export default defineComponent({ .mutate({ mutation: moveLesson, variables: { - id: eventData.data.id, input: { + id: eventData.data.id, slotStart: newStartSlotId, slotEnd: newEndSlotId, }, }, optimisticResponse: { - updateLesson: { - lesson: { - ...eventData.data, - slotStart: newStartSlot, - slotEnd: newEndSlot, - isOptimistic: true, - }, - __typename: "LessonPatchMutation", + updateLessons: { + lessons: [ + { + ...eventData.data, + slotStart: newStartSlot, + slotEnd: newEndSlot, + isOptimistic: true, + }, + ], + __typename: "LessonBatchPatchMutation", }, }, update( store, { data: { - updateLesson: { lesson }, + updateLessons: { lessons }, }, }, ) { @@ -424,14 +432,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 +464,7 @@ export default defineComponent({ const recurrenceString = rule.toString(); this.$apollo .mutate({ - mutation: createLesson, + mutation: createLessons, variables: { input: { slotStart: newStartSlotId, @@ -468,30 +478,32 @@ export default defineComponent({ }, }, optimisticResponse: { - createLesson: { - lesson: { - 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: "LessonCreateMutation", + 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", + }, + ], + __typename: "LessonBatchCreateMutation", }, }, update( store, { data: { - createLesson: { lesson }, + createLessons: { items }, }, }, ) { @@ -509,7 +521,7 @@ export default defineComponent({ return; } - storedData.lessonObjects.push(lesson); + items.forEach((lesson) => storedData.lessonObjects.push(lesson)); // Write data back to the cache store.writeQuery({ ...query, data: storedData }); @@ -558,28 +570,30 @@ export default defineComponent({ .mutate({ mutation: moveLesson, variables: { - id: lesson.id, input: { + id: lesson.id, slotStart: slotStart.id, slotEnd: slotEnd.id, }, }, optimisticResponse: { - updateLesson: { - lesson: { - ...lesson, - slotStart: slotStart, - slotEnd: slotEnd, - isOptimistic: true, - }, - __typename: "LessonPatchMutation", + updateLessons: { + lessons: [ + { + ...lesson, + slotStart: slotStart, + slotEnd: slotEnd, + isOptimistic: true, + }, + ], + __typename: "LessonBatchPatchMutation", }, }, update( store, { data: { - updateLesson: { lesson }, + updateLessons: { lessons }, }, }, ) { @@ -597,14 +611,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 +663,7 @@ export default defineComponent({ this.changeLessonSlots(lesson, lesson.slotStart, slotEnd); }, deleteLesson(lesson) { - this.itemToDelete = lesson; + this.itemsToDelete = [lesson]; this.deleteDialog = true; }, teacherClick(teacher) { @@ -705,6 +721,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; @@ -724,6 +745,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), @@ -867,7 +889,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=" @@ -969,7 +991,7 @@ export default defineComponent({ :periods="periods" :weekdays="weekdays" :lesson="overlayLesson" - :key="overlayLesson.id" + :key="'overlay-' + overlayLesson.id" /> </template> </drag-grid> @@ -1056,14 +1078,20 @@ 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> </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" @@ -1083,13 +1111,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/TimetableOverlayCard.vue b/aleksis/apps/lesrooster/frontend/components/timetable_management/TimetableOverlayCard.vue index 8d05ecb667021940d1223bd646c4d4ab9dfbf36b..92de1150203ed4deeca5a68324b22b53953cd96d 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> diff --git a/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql b/aleksis/apps/lesrooster/frontend/components/timetable_management/timetableManagement.graphql index 970c1c0be810fd48706f88722dc503063acfbdac..8f29aa75315e02433be28051c860bed2990cdcdd 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 @@ -198,9 +198,9 @@ mutation createLesson($input: CreateLessonInput!) { } } -mutation moveLesson($id: ID!, $input: PatchLessonInput!) { - updateLesson(id: $id, input: $input) { - lesson { +mutation moveLesson($input: [BatchPatchLessonInput]!) { + updateLessons(input: $input) { + 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) { - ok +mutation deleteLessons($ids: [ID]!) { + deleteLessons(ids: $ids) { + deletionCount } } diff --git a/aleksis/apps/lesrooster/frontend/components/validity_range/TimeGridField.vue b/aleksis/apps/lesrooster/frontend/components/validity_range/TimeGridField.vue index 033528208a9418de5fb573cf57d59c929caed30f..69246ca805cd43a8995de9088ef29454d2ed4e3e 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 b203b9d77cfe8a88eb771f23ee928270dc385f15..52a8156217b86c1f6bae0e71449681e4125c3693 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,12 +209,11 @@ import ValidityRangeStatusChip from "./ValidityRangeStatusChip.vue"; <script> import { validityRanges, - createValidityRange, - deleteValidityRange, + createValidityRanges, deleteValidityRanges, updateValidityRanges, - createTimeGrid, - deleteTimeGrid, + createTimeGrids, + deleteTimeGrids, } from "./validityRange.graphql"; import { gqlGroups } from "../helper.graphql"; @@ -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: "", @@ -268,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( @@ -313,22 +310,23 @@ 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 274df9db207462cf7d81edff2f94b7350e5cfd56..72ee632639fb6293d583e88d6297cc8896aebcd5 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,22 @@ 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 5c15b259d0c77e832b3b11cce0c27c1d57be05ed..7124e1491f40ef9638f84e984f72f287fb04fcb1 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 @@ -61,7 +55,7 @@ mutation deleteValidityRanges($ids: [ID]!) { } mutation updateValidityRanges($input: [BatchPatchValidityRangeInput]!) { - batchMutation: updateValidityRanges(input: $input) { + utation: updateValidityRanges(input: $input) { items: validityRanges { id name @@ -95,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 @@ -111,9 +105,9 @@ mutation createTimeGrid($input: CreateTimeGridInput!) { } } -mutation deleteTimeGrid($id: ID!) { - deleteTimeGrid(id: $id) { - ok +mutation deleteTimeGrids($ids: [ID]!) { + deleteTimeGrids(id: $ids) { + deletionCount } } diff --git a/aleksis/apps/lesrooster/frontend/index.js b/aleksis/apps/lesrooster/frontend/index.js index 1a82aec7706253dd24cc8dd41d0f29c0995abf73..5f072d5659068ce601a3a287c27a2d5b68ae7dbc 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, }, }, ], diff --git a/aleksis/apps/lesrooster/schema/__init__.py b/aleksis/apps/lesrooster/schema/__init__.py index ca3170100b2298fdbc454068d1d5ab858bbc3f75..d27e9288e94c596457496694b6955ba80cd74608 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,30 @@ from .slot import ( SlotBatchCreateMutation, SlotBatchDeleteMutation, SlotBatchPatchMutation, - SlotCreateMutation, - SlotDeleteMutation, SlotType, ) from .supervision import ( + SupervisionBatchCreateMutation, SupervisionBatchDeleteMutation, SupervisionBatchPatchMutation, - SupervisionCreateMutation, - SupervisionDeleteMutation, SupervisionType, ) from .time_grid import ( + TimeGridBatchCreateMutation, 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, ) @@ -234,7 +224,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): @@ -245,7 +235,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( @@ -262,7 +252,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): @@ -277,42 +267,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 fbc54e417fdd85dc7e626fa5cca51a0e207446d2..ed6aa19e5c51f06e2074e3de6eae7c1ffebb2ded 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 de013bc0bc4dcccd286fa3011e5aec775ee025df..a3ceb68e72cac1bdeba2940a245497373c481574 100644 --- a/aleksis/apps/lesrooster/schema/lesson.py +++ b/aleksis/apps/lesrooster/schema/lesson.py @@ -1,21 +1,18 @@ 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, PermissionBatchPatchMixin, - PermissionPatchMixin, PermissionsTypeMixin, ) @@ -47,7 +44,7 @@ class LessonType( return serialize(root.recurrence) -class LessonCreateMutation(DjangoCreateMutation): +class LessonBatchCreateMutation(DjangoBatchCreateMutation): class Meta: model = Lesson only_fields = ( @@ -68,11 +65,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 +90,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 6c2de6a501613bd058dd72a141912d644ee01b87..73f135a9b223108d1ed034b786d727c9e9750877 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 e028cf8662ccc758f2c4bbbe2574f0bf8a0bc2a7..80603a12ed15cdf8237bfb7f560c338ec14f152e 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 906b16ce6d78ab81a991b783506d6d5777569ece..a823920d1fe3cda1e19eaf6d6facb8cdc3695363 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 978260ba70e07acfcfeeac6d1223601f7a07d363..b0c1feaaaf727c8393c62352ea1415ca78245748 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, @@ -71,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): @@ -86,23 +86,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 040fc2778846be7d0e32354bd534fef0034b8880..a323858535e6fb3bc355bc3f4ca42b6f7a55aaed 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 5266c94c7c4dab90cfadb10d54e7ee7aa4ea70fc..b451c0d2f9d14f85f9ef2f7d42f5fb82be2e7783 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.dev2" +AlekSIS-Core = "^4.0.0.dev4" AlekSIS-App-Chronos = "^4.0.0.dev1" AlekSIS-App-Cursus = "^0.1.dev0" django-recurrence = "^1.11.1"