Skip to content
Snippets Groups Projects
  • Hangzhi Yu's avatar
    b83cead0
    Pass absence reasons & prevent unnecessary queries · b83cead0
    Hangzhi Yu authored and Jonathan Weth's avatar Jonathan Weth committed
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    index b9e723c2..1a064f7f 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    @@ -38,6 +38,7 @@
                       <absence-reason-buttons
                         allow-empty
                         empty-value="present"
    +                    :customAbsenceReasons="absenceReasons"
                         @input="handleMultipleAction"
                       />
                     </v-col>
    @@ -51,6 +52,7 @@
             <component
               :is="itemComponent"
               :extraMarks="extraMarks"
    +          :absenceReasons="absenceReasons"
               :documentation="item"
               :affectedQuery="lastQuery"
               :value="(selectedParticipations[item.id] ??= [])"
    @@ -85,6 +87,7 @@ import AbsenceCreationDialog from "./absences/AbsenceCreationDialog.vue";
     import { extraMarks } from "../extra_marks/extra_marks.graphql";
     import DocumentationLoader from "./documentation/DocumentationLoader.vue";
     import sendToServerMixin from "./absences/sendToServerMixin";
    +import { absenceReasons } from "./absences/absenceReasons.graphql";
    
     export default {
       name: "Coursebook",
    @@ -154,6 +157,7 @@ export default {
           currentDate: "",
           hashUpdater: false,
           extraMarks: [],
    +      absenceReasons: [],
           selectedParticipations: {},
         };
       },
    @@ -162,6 +166,10 @@ export default {
           query: extraMarks,
           update: (data) => data.items,
         },
    +    absenceReasons: {
    +      query: absenceReasons,
    +      update: (data) => data.items,
    +    },
       },
       computed: {
         // Assertion: Should only fire on page load or selection change.
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    index 1e092b4e..f639e731 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    @@ -7,6 +7,8 @@
           <documentation-absences
             compact
             v-bind="$attrs"
    +        :extra-marks="extraMarks"
    +        :absence-reasons="absenceReasons"
             :dialog-activator="activator"
             :value="value"
             @input="$emit('input', $event)"
    @@ -14,7 +16,12 @@
         </template>
         <!-- dialog view -> deactivate dialog -->
         <!-- cancel | save (through lesson-summary) -->
    -    <documentation v-bind="$attrs" @close="popup = false" />
    +    <documentation
    +      v-bind="$attrs"
    +      :extra-marks="extraMarks"
    +      :absence-reasons="absenceReasons"
    +      @close="popup = false"
    +    />
       </mobile-fullscreen-dialog>
     </template>
    
    @@ -40,6 +47,14 @@ export default {
           type: Array,
           required: true,
         },
    +    extraMarks: {
    +      type: Array,
    +      required: true,
    +    },
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
     };
     </script>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    index aa9176a8..66585b43 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    @@ -12,6 +12,7 @@ import PersonalNotes from "../personal_notes/PersonalNotes.vue";
     import ExtraMarkChip from "../../extra_marks/ExtraMarkChip.vue";
     import TardinessChip from "./TardinessChip.vue";
     import TardinessField from "./TardinessField.vue";
    +import documentationPartMixin from "../documentation/documentationPartMixin";
    
     export default {
       name: "ManageStudentsDialog",
    @@ -179,9 +180,9 @@ export default {
               <v-card-text>
                 <absence-reason-group-select
                   allow-empty
    -              empty-value="present"
                   :loadSelectedChip="loading"
                   :value="item.absenceReason?.id || 'present'"
    +              :customAbsenceReasons="absenceReasons"
                   @input="sendToServer([item], 'absenceReason', $event)"
                 />
                 <tardiness-field
    @@ -212,6 +213,7 @@ export default {
               <absence-reason-buttons
                 allow-empty
                 empty-value="present"
    +            :customAbsenceReasons="absenceReasons"
                 @input="handleMultipleAction"
               />
             </div>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    index 0b3f650d..91feed9e 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    @@ -26,8 +26,8 @@ import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReas
                     v-if="participation.absenceReason && !compact"
                     class="full-width"
                     allow-empty
    -                empty-value="present"
                     :loadSelectedChip="loading"
    +                :customAbsenceReasons="absenceReasons"
                     :value="participation.absenceReason?.id || 'present'"
                     @input="sendToServer([participation], 'absenceReason', $event)"
                   />
    @@ -35,8 +35,8 @@ import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReas
                 <v-list-item-action v-if="participation.absenceReason && compact">
                   <absence-reason-group-select
                     allow-empty
    -                empty-value="present"
                     :loadSelectedChip="loading"
    +                :customAbsenceReasons="absenceReasons"
                     :value="participation.absenceReason?.id || 'present'"
                     @input="sendToServer([participation], 'absenceReason', $event)"
                   />
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql
    new file mode 100644
    index 00000000..2a651a96
    --- /dev/null
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql
    @@ -0,0 +1,11 @@
    +query absenceReasons($orderBy: [String], $filters: JSONString) {
    +  items: absenceReasons(orderBy: $orderBy, filters: $filters) {
    +    id
    +    shortName
    +    name
    +    colour
    +    default
    +    canEdit
    +    canDelete
    +  }
    +}
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    index a679830c..177e886f 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    @@ -9,6 +9,7 @@
             v-bind="$attrs"
             :dialog-activator="activator"
             :extra-marks="extraMarks"
    +        :absence-reasons="absenceReasons"
           />
         </template>
         <!-- dialog view -> deactivate dialog -->
    @@ -16,6 +17,7 @@
         <documentation
           v-bind="$attrs"
           :extra-marks="extraMarks"
    +      :absence-reasons="absenceReasons"
           @close="popup = false"
         />
       </mobile-fullscreen-dialog>
    @@ -41,6 +43,10 @@ export default {
           type: Array,
           required: true,
         },
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
     };
     </script>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    index 35243ee3..886803b4 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    @@ -40,6 +40,13 @@ export default {
           type: Array,
           required: true,
         },
    +    /**
    +     * Once loaded list of absence reasons to avoid excessive network and database queries
    +     */
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
    
       computed: {
    @@ -54,6 +61,7 @@ export default {
             dialogActivator: this.dialogActivator,
             affectedQuery: this.affectedQuery,
             extraMarks: this.extraMarks,
    +        absenceReasons: this.absenceReasons,
           };
         },
       },
    
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    index 7ab16ac1..7a669f7f 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    @@ -38,6 +38,7 @@
                       <absence-reason-buttons
                         allow-empty
                         empty-value="present"
    +                    :customAbsenceReasons="absenceReasons"
                         @input="handleMultipleAction"
                       />
                     </v-col>
    @@ -51,6 +52,7 @@
             <component
               :is="itemComponent"
               :extra-marks="extraMarks"
    +          :absenceReasons="absenceReasons"
               :documentation="item"
               :affected-query="lastQuery"
               :value="(selectedParticipations[item.id] ??= [])"
    @@ -84,6 +86,7 @@ import AbsenceCreationDialog from "./absences/AbsenceCreationDialog.vue";
     import { extraMarks } from "../extra_marks/extra_marks.graphql";
     import DocumentationLoader from "./documentation/DocumentationLoader.vue";
     import sendToServerMixin from "./absences/sendToServerMixin";
    +import { absenceReasons } from "./absences/absenceReasons.graphql";
    
     export default {
       name: "Coursebook",
    @@ -153,6 +156,7 @@ export default {
           currentDate: "",
           hashUpdater: false,
           extraMarks: [],
    +      absenceReasons: [],
           selectedParticipations: {},
         };
       },
    @@ -161,6 +165,10 @@ export default {
           query: extraMarks,
           update: (data) => data.items,
         },
    +    absenceReasons: {
    +      query: absenceReasons,
    +      update: (data) => data.items,
    +    },
       },
       computed: {
         // Assertion: Should only fire on page load or selection change.
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    index 1e092b4e..f639e731 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    @@ -7,6 +7,8 @@
           <documentation-absences
             compact
             v-bind="$attrs"
    +        :extra-marks="extraMarks"
    +        :absence-reasons="absenceReasons"
             :dialog-activator="activator"
             :value="value"
             @input="$emit('input', $event)"
    @@ -14,7 +16,12 @@
         </template>
         <!-- dialog view -> deactivate dialog -->
         <!-- cancel | save (through lesson-summary) -->
    -    <documentation v-bind="$attrs" @close="popup = false" />
    +    <documentation
    +      v-bind="$attrs"
    +      :extra-marks="extraMarks"
    +      :absence-reasons="absenceReasons"
    +      @close="popup = false"
    +    />
       </mobile-fullscreen-dialog>
     </template>
    
    @@ -40,6 +47,14 @@ export default {
           type: Array,
           required: true,
         },
    +    extraMarks: {
    +      type: Array,
    +      required: true,
    +    },
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
     };
     </script>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    index d8f001d3..a5d663d3 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    @@ -179,9 +179,9 @@ export default {
               <v-card-text>
                 <absence-reason-group-select
                   allow-empty
    -              empty-value="present"
                   :load-selected-chip="loading"
                   :value="item.absenceReason?.id || 'present'"
    +              :customAbsenceReasons="absenceReasons"
                   @input="sendToServer([item], 'absenceReason', $event)"
                 />
                 <tardiness-field
    @@ -212,6 +212,7 @@ export default {
               <absence-reason-buttons
                 allow-empty
                 empty-value="present"
    +            :customAbsenceReasons="absenceReasons"
                 @input="handleMultipleAction"
               />
             </div>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    index 1c941b8d..26adb589 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    @@ -26,8 +26,8 @@ import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReas
                     v-if="participation.absenceReason && !compact"
                     class="full-width"
                     allow-empty
    -                empty-value="present"
                     :load-selected-chip="loading"
    +                :customAbsenceReasons="absenceReasons"
                     :value="participation.absenceReason?.id || 'present'"
                     @input="sendToServer([participation], 'absenceReason', $event)"
                   />
    @@ -35,8 +35,8 @@ import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReas
                 <v-list-item-action v-if="participation.absenceReason && compact">
                   <absence-reason-group-select
                     allow-empty
    -                empty-value="present"
                     :load-selected-chip="loading"
    +                :customAbsenceReasons="absenceReasons"
                     :value="participation.absenceReason?.id || 'present'"
                     @input="sendToServer([participation], 'absenceReason', $event)"
                   />
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql
    new file mode 100644
    index 00000000..2a651a96
    --- /dev/null
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql
    @@ -0,0 +1,11 @@
    +query absenceReasons($orderBy: [String], $filters: JSONString) {
    +  items: absenceReasons(orderBy: $orderBy, filters: $filters) {
    +    id
    +    shortName
    +    name
    +    colour
    +    default
    +    canEdit
    +    canDelete
    +  }
    +}
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    index a679830c..177e886f 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    @@ -9,6 +9,7 @@
             v-bind="$attrs"
             :dialog-activator="activator"
             :extra-marks="extraMarks"
    +        :absence-reasons="absenceReasons"
           />
         </template>
         <!-- dialog view -> deactivate dialog -->
    @@ -16,6 +17,7 @@
         <documentation
           v-bind="$attrs"
           :extra-marks="extraMarks"
    +      :absence-reasons="absenceReasons"
           @close="popup = false"
         />
       </mobile-fullscreen-dialog>
    @@ -41,6 +43,10 @@ export default {
           type: Array,
           required: true,
         },
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
     };
     </script>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    index 35243ee3..886803b4 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    @@ -40,6 +40,13 @@ export default {
           type: Array,
           required: true,
         },
    +    /**
    +     * Once loaded list of absence reasons to avoid excessive network and database queries
    +     */
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
    
       computed: {
    @@ -54,6 +61,7 @@ export default {
             dialogActivator: this.dialogActivator,
             affectedQuery: this.affectedQuery,
             extraMarks: this.extraMarks,
    +        absenceReasons: this.absenceReasons,
           };
         },
       },
    b83cead0
    History
    Pass absence reasons & prevent unnecessary queries
    Hangzhi Yu authored and Jonathan Weth's avatar Jonathan Weth committed
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    index b9e723c2..1a064f7f 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    @@ -38,6 +38,7 @@
                       <absence-reason-buttons
                         allow-empty
                         empty-value="present"
    +                    :customAbsenceReasons="absenceReasons"
                         @input="handleMultipleAction"
                       />
                     </v-col>
    @@ -51,6 +52,7 @@
             <component
               :is="itemComponent"
               :extraMarks="extraMarks"
    +          :absenceReasons="absenceReasons"
               :documentation="item"
               :affectedQuery="lastQuery"
               :value="(selectedParticipations[item.id] ??= [])"
    @@ -85,6 +87,7 @@ import AbsenceCreationDialog from "./absences/AbsenceCreationDialog.vue";
     import { extraMarks } from "../extra_marks/extra_marks.graphql";
     import DocumentationLoader from "./documentation/DocumentationLoader.vue";
     import sendToServerMixin from "./absences/sendToServerMixin";
    +import { absenceReasons } from "./absences/absenceReasons.graphql";
    
     export default {
       name: "Coursebook",
    @@ -154,6 +157,7 @@ export default {
           currentDate: "",
           hashUpdater: false,
           extraMarks: [],
    +      absenceReasons: [],
           selectedParticipations: {},
         };
       },
    @@ -162,6 +166,10 @@ export default {
           query: extraMarks,
           update: (data) => data.items,
         },
    +    absenceReasons: {
    +      query: absenceReasons,
    +      update: (data) => data.items,
    +    },
       },
       computed: {
         // Assertion: Should only fire on page load or selection change.
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    index 1e092b4e..f639e731 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    @@ -7,6 +7,8 @@
           <documentation-absences
             compact
             v-bind="$attrs"
    +        :extra-marks="extraMarks"
    +        :absence-reasons="absenceReasons"
             :dialog-activator="activator"
             :value="value"
             @input="$emit('input', $event)"
    @@ -14,7 +16,12 @@
         </template>
         <!-- dialog view -> deactivate dialog -->
         <!-- cancel | save (through lesson-summary) -->
    -    <documentation v-bind="$attrs" @close="popup = false" />
    +    <documentation
    +      v-bind="$attrs"
    +      :extra-marks="extraMarks"
    +      :absence-reasons="absenceReasons"
    +      @close="popup = false"
    +    />
       </mobile-fullscreen-dialog>
     </template>
    
    @@ -40,6 +47,14 @@ export default {
           type: Array,
           required: true,
         },
    +    extraMarks: {
    +      type: Array,
    +      required: true,
    +    },
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
     };
     </script>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    index aa9176a8..66585b43 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    @@ -12,6 +12,7 @@ import PersonalNotes from "../personal_notes/PersonalNotes.vue";
     import ExtraMarkChip from "../../extra_marks/ExtraMarkChip.vue";
     import TardinessChip from "./TardinessChip.vue";
     import TardinessField from "./TardinessField.vue";
    +import documentationPartMixin from "../documentation/documentationPartMixin";
    
     export default {
       name: "ManageStudentsDialog",
    @@ -179,9 +180,9 @@ export default {
               <v-card-text>
                 <absence-reason-group-select
                   allow-empty
    -              empty-value="present"
                   :loadSelectedChip="loading"
                   :value="item.absenceReason?.id || 'present'"
    +              :customAbsenceReasons="absenceReasons"
                   @input="sendToServer([item], 'absenceReason', $event)"
                 />
                 <tardiness-field
    @@ -212,6 +213,7 @@ export default {
               <absence-reason-buttons
                 allow-empty
                 empty-value="present"
    +            :customAbsenceReasons="absenceReasons"
                 @input="handleMultipleAction"
               />
             </div>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    index 0b3f650d..91feed9e 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    @@ -26,8 +26,8 @@ import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReas
                     v-if="participation.absenceReason && !compact"
                     class="full-width"
                     allow-empty
    -                empty-value="present"
                     :loadSelectedChip="loading"
    +                :customAbsenceReasons="absenceReasons"
                     :value="participation.absenceReason?.id || 'present'"
                     @input="sendToServer([participation], 'absenceReason', $event)"
                   />
    @@ -35,8 +35,8 @@ import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReas
                 <v-list-item-action v-if="participation.absenceReason && compact">
                   <absence-reason-group-select
                     allow-empty
    -                empty-value="present"
                     :loadSelectedChip="loading"
    +                :customAbsenceReasons="absenceReasons"
                     :value="participation.absenceReason?.id || 'present'"
                     @input="sendToServer([participation], 'absenceReason', $event)"
                   />
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql
    new file mode 100644
    index 00000000..2a651a96
    --- /dev/null
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql
    @@ -0,0 +1,11 @@
    +query absenceReasons($orderBy: [String], $filters: JSONString) {
    +  items: absenceReasons(orderBy: $orderBy, filters: $filters) {
    +    id
    +    shortName
    +    name
    +    colour
    +    default
    +    canEdit
    +    canDelete
    +  }
    +}
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    index a679830c..177e886f 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    @@ -9,6 +9,7 @@
             v-bind="$attrs"
             :dialog-activator="activator"
             :extra-marks="extraMarks"
    +        :absence-reasons="absenceReasons"
           />
         </template>
         <!-- dialog view -> deactivate dialog -->
    @@ -16,6 +17,7 @@
         <documentation
           v-bind="$attrs"
           :extra-marks="extraMarks"
    +      :absence-reasons="absenceReasons"
           @close="popup = false"
         />
       </mobile-fullscreen-dialog>
    @@ -41,6 +43,10 @@ export default {
           type: Array,
           required: true,
         },
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
     };
     </script>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    index 35243ee3..886803b4 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    @@ -40,6 +40,13 @@ export default {
           type: Array,
           required: true,
         },
    +    /**
    +     * Once loaded list of absence reasons to avoid excessive network and database queries
    +     */
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
    
       computed: {
    @@ -54,6 +61,7 @@ export default {
             dialogActivator: this.dialogActivator,
             affectedQuery: this.affectedQuery,
             extraMarks: this.extraMarks,
    +        absenceReasons: this.absenceReasons,
           };
         },
       },
    
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    index 7ab16ac1..7a669f7f 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
    @@ -38,6 +38,7 @@
                       <absence-reason-buttons
                         allow-empty
                         empty-value="present"
    +                    :customAbsenceReasons="absenceReasons"
                         @input="handleMultipleAction"
                       />
                     </v-col>
    @@ -51,6 +52,7 @@
             <component
               :is="itemComponent"
               :extra-marks="extraMarks"
    +          :absenceReasons="absenceReasons"
               :documentation="item"
               :affected-query="lastQuery"
               :value="(selectedParticipations[item.id] ??= [])"
    @@ -84,6 +86,7 @@ import AbsenceCreationDialog from "./absences/AbsenceCreationDialog.vue";
     import { extraMarks } from "../extra_marks/extra_marks.graphql";
     import DocumentationLoader from "./documentation/DocumentationLoader.vue";
     import sendToServerMixin from "./absences/sendToServerMixin";
    +import { absenceReasons } from "./absences/absenceReasons.graphql";
    
     export default {
       name: "Coursebook",
    @@ -153,6 +156,7 @@ export default {
           currentDate: "",
           hashUpdater: false,
           extraMarks: [],
    +      absenceReasons: [],
           selectedParticipations: {},
         };
       },
    @@ -161,6 +165,10 @@ export default {
           query: extraMarks,
           update: (data) => data.items,
         },
    +    absenceReasons: {
    +      query: absenceReasons,
    +      update: (data) => data.items,
    +    },
       },
       computed: {
         // Assertion: Should only fire on page load or selection change.
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    index 1e092b4e..f639e731 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/DocumentationAbsencesModal.vue
    @@ -7,6 +7,8 @@
           <documentation-absences
             compact
             v-bind="$attrs"
    +        :extra-marks="extraMarks"
    +        :absence-reasons="absenceReasons"
             :dialog-activator="activator"
             :value="value"
             @input="$emit('input', $event)"
    @@ -14,7 +16,12 @@
         </template>
         <!-- dialog view -> deactivate dialog -->
         <!-- cancel | save (through lesson-summary) -->
    -    <documentation v-bind="$attrs" @close="popup = false" />
    +    <documentation
    +      v-bind="$attrs"
    +      :extra-marks="extraMarks"
    +      :absence-reasons="absenceReasons"
    +      @close="popup = false"
    +    />
       </mobile-fullscreen-dialog>
     </template>
    
    @@ -40,6 +47,14 @@ export default {
           type: Array,
           required: true,
         },
    +    extraMarks: {
    +      type: Array,
    +      required: true,
    +    },
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
     };
     </script>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    index d8f001d3..a5d663d3 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
    @@ -179,9 +179,9 @@ export default {
               <v-card-text>
                 <absence-reason-group-select
                   allow-empty
    -              empty-value="present"
                   :load-selected-chip="loading"
                   :value="item.absenceReason?.id || 'present'"
    +              :customAbsenceReasons="absenceReasons"
                   @input="sendToServer([item], 'absenceReason', $event)"
                 />
                 <tardiness-field
    @@ -212,6 +212,7 @@ export default {
               <absence-reason-buttons
                 allow-empty
                 empty-value="present"
    +            :customAbsenceReasons="absenceReasons"
                 @input="handleMultipleAction"
               />
             </div>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    index 1c941b8d..26adb589 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ParticipationList.vue
    @@ -26,8 +26,8 @@ import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReas
                     v-if="participation.absenceReason && !compact"
                     class="full-width"
                     allow-empty
    -                empty-value="present"
                     :load-selected-chip="loading"
    +                :customAbsenceReasons="absenceReasons"
                     :value="participation.absenceReason?.id || 'present'"
                     @input="sendToServer([participation], 'absenceReason', $event)"
                   />
    @@ -35,8 +35,8 @@ import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReas
                 <v-list-item-action v-if="participation.absenceReason && compact">
                   <absence-reason-group-select
                     allow-empty
    -                empty-value="present"
                     :load-selected-chip="loading"
    +                :customAbsenceReasons="absenceReasons"
                     :value="participation.absenceReason?.id || 'present'"
                     @input="sendToServer([participation], 'absenceReason', $event)"
                   />
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql
    new file mode 100644
    index 00000000..2a651a96
    --- /dev/null
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceReasons.graphql
    @@ -0,0 +1,11 @@
    +query absenceReasons($orderBy: [String], $filters: JSONString) {
    +  items: absenceReasons(orderBy: $orderBy, filters: $filters) {
    +    id
    +    shortName
    +    name
    +    colour
    +    default
    +    canEdit
    +    canDelete
    +  }
    +}
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    index a679830c..177e886f 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/DocumentationModal.vue
    @@ -9,6 +9,7 @@
             v-bind="$attrs"
             :dialog-activator="activator"
             :extra-marks="extraMarks"
    +        :absence-reasons="absenceReasons"
           />
         </template>
         <!-- dialog view -> deactivate dialog -->
    @@ -16,6 +17,7 @@
         <documentation
           v-bind="$attrs"
           :extra-marks="extraMarks"
    +      :absence-reasons="absenceReasons"
           @close="popup = false"
         />
       </mobile-fullscreen-dialog>
    @@ -41,6 +43,10 @@ export default {
           type: Array,
           required: true,
         },
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
     };
     </script>
    diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    index 35243ee3..886803b4 100644
    --- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    +++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/documentationPartMixin.js
    @@ -40,6 +40,13 @@ export default {
           type: Array,
           required: true,
         },
    +    /**
    +     * Once loaded list of absence reasons to avoid excessive network and database queries
    +     */
    +    absenceReasons: {
    +      type: Array,
    +      required: true,
    +    },
       },
    
       computed: {
    @@ -54,6 +61,7 @@ export default {
             dialogActivator: this.dialogActivator,
             affectedQuery: this.affectedQuery,
             extraMarks: this.extraMarks,
    +        absenceReasons: this.absenceReasons,
           };
         },
       },