From b72cc1dda20ffc49982029920fe6826eb96f5160 Mon Sep 17 00:00:00 2001
From: Hangzhi Yu <hangzhi@protonmail.com>
Date: Wed, 22 May 2024 20:38:39 +0200
Subject: [PATCH 1/5] Add TeacherField

---
 .../frontend/components/TeacherField.vue      | 78 +++++++++++++++++++
 .../cursus/frontend/components/helper.graphql |  8 ++
 aleksis/apps/cursus/frontend/messages/en.json |  6 ++
 3 files changed, 92 insertions(+)
 create mode 100644 aleksis/apps/cursus/frontend/components/TeacherField.vue

diff --git a/aleksis/apps/cursus/frontend/components/TeacherField.vue b/aleksis/apps/cursus/frontend/components/TeacherField.vue
new file mode 100644
index 0000000..5bfcf75
--- /dev/null
+++ b/aleksis/apps/cursus/frontend/components/TeacherField.vue
@@ -0,0 +1,78 @@
+<template>
+  <v-autocomplete
+    v-bind="$attrs"
+    v-on="$listeners"
+    multiple
+    :items="getTeacherList"
+    item-text="fullName"
+    item-value="id"
+    :loading="$apollo.queries.persons.loading"
+  >
+    <template #item="data">
+      <template v-if="typeof data.item !== 'object'">
+        <v-list-item-content>{{ data.item }}</v-list-item-content>
+      </template>
+      <template v-else>
+        <v-list-item-action>
+          <v-checkbox v-model="data.attrs.inputValue" />
+        </v-list-item-action>
+        <v-list-item-content>
+          <v-list-item-title>{{ data.item.fullName }}</v-list-item-title>
+          <v-list-item-subtitle v-if="data.item.shortName">{{
+            data.item.shortName
+          }}</v-list-item-subtitle>
+        </v-list-item-content>
+      </template>
+    </template>
+    <template #prepend-inner>
+      <slot name="prepend-inner" />
+    </template>
+    <template #selection="data">
+      <slot name="selection" v-bind="data" />
+    </template>
+  </v-autocomplete>
+</template>
+
+<script>
+import { gqlTeachers } from "./helper.graphql";
+
+export default {
+  name: "TeacherField",
+  data() {
+    return {
+      persons: [],
+    };
+  },
+  props: {
+    subject: {
+      type: Object,
+      required: true,
+    },
+  },
+  computed: {
+    getTeacherList() {
+      return [
+        {
+          header: this.$t("cursus.teacher.field.subject_teachers"),
+        },
+        ...this.persons.filter((person) =>
+          this.subject.teachers.find((teacher) => teacher.id === person.id),
+        ),
+        { divider: true },
+        { header: this.$t("cursus.teacher.field.all_teachers") },
+        ...this.persons.filter(
+          (person) =>
+            !this.subject.teachers.find((teacher) => teacher.id === person.id),
+        ),
+      ];
+    },
+  },
+  apollo: {
+    persons: {
+      query: gqlTeachers,
+    },
+  },
+};
+</script>
+
+<style scoped></style>
diff --git a/aleksis/apps/cursus/frontend/components/helper.graphql b/aleksis/apps/cursus/frontend/components/helper.graphql
index b849f56..37a5315 100644
--- a/aleksis/apps/cursus/frontend/components/helper.graphql
+++ b/aleksis/apps/cursus/frontend/components/helper.graphql
@@ -12,3 +12,11 @@ query gqlGroups {
     name
   }
 }
+
+query gqlTeachers {
+  persons: teachers {
+    id
+    fullName
+    shortName
+  }
+}
diff --git a/aleksis/apps/cursus/frontend/messages/en.json b/aleksis/apps/cursus/frontend/messages/en.json
index 9e257d3..44c87b5 100644
--- a/aleksis/apps/cursus/frontend/messages/en.json
+++ b/aleksis/apps/cursus/frontend/messages/en.json
@@ -43,6 +43,12 @@
       },
       "timetable": "Timetable"
     },
+    "teacher": {
+      "field": {
+        "subject_teachers": "Teachers for subject",
+        "all_teachers": "All teachers"
+      }
+    },
     "errors": {
       "short_name_required": "Short name is required",
       "name_required": "Name is required",
-- 
GitLab


From 7cc8cf1b4de63af3fb4cc640e31a65170fdea5c0 Mon Sep 17 00:00:00 2001
From: Hangzhi Yu <hangzhi@protonmail.com>
Date: Wed, 29 May 2024 16:53:43 +0200
Subject: [PATCH 2/5] Change naming of computed teacher property

---
 aleksis/apps/cursus/frontend/components/TeacherField.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/aleksis/apps/cursus/frontend/components/TeacherField.vue b/aleksis/apps/cursus/frontend/components/TeacherField.vue
index 5bfcf75..c9a95d5 100644
--- a/aleksis/apps/cursus/frontend/components/TeacherField.vue
+++ b/aleksis/apps/cursus/frontend/components/TeacherField.vue
@@ -3,7 +3,7 @@
     v-bind="$attrs"
     v-on="$listeners"
     multiple
-    :items="getTeacherList"
+    :items="teacherList"
     item-text="fullName"
     item-value="id"
     :loading="$apollo.queries.persons.loading"
@@ -50,7 +50,7 @@ export default {
     },
   },
   computed: {
-    getTeacherList() {
+    teacherList() {
       return [
         {
           header: this.$t("cursus.teacher.field.subject_teachers"),
-- 
GitLab


From 63aecefa07b575cd22f4a47dc5c01c3e665037a3 Mon Sep 17 00:00:00 2001
From: Hangzhi Yu <hangzhi@protonmail.com>
Date: Thu, 30 May 2024 02:17:59 +0200
Subject: [PATCH 3/5] Refactor teacher select field

---
 .../frontend/components/SubjectChip.vue       |  6 ++
 .../frontend/components/TeacherField.vue      | 77 +++++++++++--------
 .../cursus/frontend/components/helper.graphql |  7 ++
 aleksis/apps/cursus/frontend/messages/en.json |  6 --
 aleksis/apps/cursus/schema.py                 | 18 ++++-
 5 files changed, 77 insertions(+), 37 deletions(-)

diff --git a/aleksis/apps/cursus/frontend/components/SubjectChip.vue b/aleksis/apps/cursus/frontend/components/SubjectChip.vue
index d92ff83..74634c8 100644
--- a/aleksis/apps/cursus/frontend/components/SubjectChip.vue
+++ b/aleksis/apps/cursus/frontend/components/SubjectChip.vue
@@ -12,6 +12,11 @@ export default {
       required: false,
       default: false,
     },
+    prependIcon: {
+      type: String,
+      default: null,
+      required: false,
+    },
     appendIcon: {
       type: String,
       default: null,
@@ -28,6 +33,7 @@ export default {
     :color="subject.colourBg"
     :text-color="subject.colourFg"
   >
+    <v-icon left v-if="prependIcon">{{ prependIcon }}</v-icon>
     {{ shortName ? subject.shortName : subject.name }}
     <v-icon right v-if="appendIcon">{{ appendIcon }}</v-icon>
   </v-chip>
diff --git a/aleksis/apps/cursus/frontend/components/TeacherField.vue b/aleksis/apps/cursus/frontend/components/TeacherField.vue
index c9a95d5..83b1485 100644
--- a/aleksis/apps/cursus/frontend/components/TeacherField.vue
+++ b/aleksis/apps/cursus/frontend/components/TeacherField.vue
@@ -1,3 +1,7 @@
+<script setup>
+import SubjectChip from "./SubjectChip.vue";
+</script>
+
 <template>
   <v-autocomplete
     v-bind="$attrs"
@@ -9,20 +13,25 @@
     :loading="$apollo.queries.persons.loading"
   >
     <template #item="data">
-      <template v-if="typeof data.item !== 'object'">
-        <v-list-item-content>{{ data.item }}</v-list-item-content>
-      </template>
-      <template v-else>
-        <v-list-item-action>
-          <v-checkbox v-model="data.attrs.inputValue" />
-        </v-list-item-action>
-        <v-list-item-content>
-          <v-list-item-title>{{ data.item.fullName }}</v-list-item-title>
-          <v-list-item-subtitle v-if="data.item.shortName">{{
-            data.item.shortName
-          }}</v-list-item-subtitle>
-        </v-list-item-content>
-      </template>
+      <v-list-item-action>
+        <v-checkbox v-model="data.attrs.inputValue" />
+      </v-list-item-action>
+      <v-list-item-content>
+        <v-list-item-title>{{ data.item.fullName }}</v-list-item-title>
+        <v-list-item-subtitle v-if="data.item.shortName">{{
+          data.item.shortName
+        }}
+        </v-list-item-subtitle>
+        <v-list-item-subtitle v-if="showSubjects && data.item.subjectsAsTeacher.length">
+          <subject-chip
+          v-for="subject in data.item.subjectsAsTeacher"
+          :subject="subject"
+          :prepend-icon="subject.id === prioritySubject.id ? '$success' : ''"
+          :short-name="true"
+          x-small
+          />
+        </v-list-item-subtitle>
+      </v-list-item-content>
     </template>
     <template #prepend-inner>
       <slot name="prepend-inner" />
@@ -44,27 +53,35 @@ export default {
     };
   },
   props: {
-    subject: {
+    showSubjects: {
+      type: Boolean,
+      required: false,
+      default: false,
+    },
+    prioritySubject: {
       type: Object,
-      required: true,
+      required: false,
+      default: null,
     },
   },
   computed: {
     teacherList() {
-      return [
-        {
-          header: this.$t("cursus.teacher.field.subject_teachers"),
-        },
-        ...this.persons.filter((person) =>
-          this.subject.teachers.find((teacher) => teacher.id === person.id),
-        ),
-        { divider: true },
-        { header: this.$t("cursus.teacher.field.all_teachers") },
-        ...this.persons.filter(
-          (person) =>
-            !this.subject.teachers.find((teacher) => teacher.id === person.id),
-        ),
-      ];
+      if (this.prioritySubject) {
+        let matching = [];
+        let nonMatching = [];
+
+        this.persons.forEach((p) => {
+          if (p.subjectsAsTeacher.some((s) => s.id === this.prioritySubject.id)) {
+            matching.push(p);
+          } else {
+            nonMatching.push(p);
+          }
+        });
+
+        return matching.concat(nonMatching);
+      } else {
+        return this.persons;
+      }
     },
   },
   apollo: {
diff --git a/aleksis/apps/cursus/frontend/components/helper.graphql b/aleksis/apps/cursus/frontend/components/helper.graphql
index 37a5315..433ff5c 100644
--- a/aleksis/apps/cursus/frontend/components/helper.graphql
+++ b/aleksis/apps/cursus/frontend/components/helper.graphql
@@ -18,5 +18,12 @@ query gqlTeachers {
     id
     fullName
     shortName
+    subjectsAsTeacher {
+      id
+      name
+      shortName
+      colourFg
+      colourBg
+    }
   }
 }
diff --git a/aleksis/apps/cursus/frontend/messages/en.json b/aleksis/apps/cursus/frontend/messages/en.json
index 44c87b5..9e257d3 100644
--- a/aleksis/apps/cursus/frontend/messages/en.json
+++ b/aleksis/apps/cursus/frontend/messages/en.json
@@ -43,12 +43,6 @@
       },
       "timetable": "Timetable"
     },
-    "teacher": {
-      "field": {
-        "subject_teachers": "Teachers for subject",
-        "all_teachers": "All teachers"
-      }
-    },
     "errors": {
       "short_name_required": "Short name is required",
       "name_required": "Name is required",
diff --git a/aleksis/apps/cursus/schema.py b/aleksis/apps/cursus/schema.py
index 711ddd0..275ee67 100644
--- a/aleksis/apps/cursus/schema.py
+++ b/aleksis/apps/cursus/schema.py
@@ -159,6 +159,22 @@ class CourseType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectType):
         # return get_objects_for_user(info.context.user, "cursus.view_course", Course)
 
 
+class TeacherType(GraphQLPersonType):
+    class Meta:
+        model = Person
+
+    subjects_as_teacher = graphene.List(SubjectType)
+    courses_as_teacher = graphene.List(CourseType)
+
+    @staticmethod
+    def resolve_subjects_as_teacher(root, info, **kwargs):
+        return root.subjects_as_teacher.all()
+
+    @staticmethod
+    def resolve_courses_as_teacher(root, info, **kwargs):
+        return root.courses_as_teacher.all()
+
+
 class CourseBatchCreateMutation(DjangoBatchCreateMutation):
     class Meta:
         model = Course
@@ -215,7 +231,7 @@ class Query(graphene.ObjectType):
     school_grades = FilterOrderList(GraphQLGroupType)
     school_grades_by_term = FilterOrderList(GraphQLGroupType, school_term=graphene.ID())
 
-    teachers = FilterOrderList(GraphQLPersonType)
+    teachers = FilterOrderList(TeacherType)
 
     course_by_id = graphene.Field(CourseType, id=graphene.ID())
     courses_of_teacher = FilterOrderList(CourseType, teacher=graphene.ID())
-- 
GitLab


From e96d277f001be46437cc4446dd9005eb2973b459 Mon Sep 17 00:00:00 2001
From: Hangzhi Yu <hangzhi@protonmail.com>
Date: Fri, 31 May 2024 13:32:01 +0200
Subject: [PATCH 4/5] Add margin between subject chips

---
 aleksis/apps/cursus/frontend/components/TeacherField.vue | 1 +
 1 file changed, 1 insertion(+)

diff --git a/aleksis/apps/cursus/frontend/components/TeacherField.vue b/aleksis/apps/cursus/frontend/components/TeacherField.vue
index 83b1485..90f22e2 100644
--- a/aleksis/apps/cursus/frontend/components/TeacherField.vue
+++ b/aleksis/apps/cursus/frontend/components/TeacherField.vue
@@ -29,6 +29,7 @@ import SubjectChip from "./SubjectChip.vue";
           :prepend-icon="subject.id === prioritySubject.id ? '$success' : ''"
           :short-name="true"
           x-small
+          class="mr-1"
           />
         </v-list-item-subtitle>
       </v-list-item-content>
-- 
GitLab


From c7b2ad13c7b24f964bdd81de74b15896f46bfae2 Mon Sep 17 00:00:00 2001
From: Hangzhi Yu <hangzhi@protonmail.com>
Date: Fri, 31 May 2024 13:32:54 +0200
Subject: [PATCH 5/5] Reformat

---
 .../frontend/components/TeacherField.vue      | 26 +++++++++++--------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/aleksis/apps/cursus/frontend/components/TeacherField.vue b/aleksis/apps/cursus/frontend/components/TeacherField.vue
index 90f22e2..8331d02 100644
--- a/aleksis/apps/cursus/frontend/components/TeacherField.vue
+++ b/aleksis/apps/cursus/frontend/components/TeacherField.vue
@@ -18,18 +18,20 @@ import SubjectChip from "./SubjectChip.vue";
       </v-list-item-action>
       <v-list-item-content>
         <v-list-item-title>{{ data.item.fullName }}</v-list-item-title>
-        <v-list-item-subtitle v-if="data.item.shortName">{{
-          data.item.shortName
-        }}
+        <v-list-item-subtitle v-if="data.item.shortName"
+          >{{ data.item.shortName }}
         </v-list-item-subtitle>
-        <v-list-item-subtitle v-if="showSubjects && data.item.subjectsAsTeacher.length">
+        <v-list-item-subtitle
+          v-if="showSubjects && data.item.subjectsAsTeacher.length"
+        >
           <subject-chip
-          v-for="subject in data.item.subjectsAsTeacher"
-          :subject="subject"
-          :prepend-icon="subject.id === prioritySubject.id ? '$success' : ''"
-          :short-name="true"
-          x-small
-          class="mr-1"
+            v-for="subject in data.item.subjectsAsTeacher"
+            :key="subject.id"
+            :subject="subject"
+            :prepend-icon="subject.id === prioritySubject.id ? '$success' : ''"
+            :short-name="true"
+            x-small
+            class="mr-1"
           />
         </v-list-item-subtitle>
       </v-list-item-content>
@@ -72,7 +74,9 @@ export default {
         let nonMatching = [];
 
         this.persons.forEach((p) => {
-          if (p.subjectsAsTeacher.some((s) => s.id === this.prioritySubject.id)) {
+          if (
+            p.subjectsAsTeacher.some((s) => s.id === this.prioritySubject.id)
+          ) {
             matching.push(p);
           } else {
             nonMatching.push(p);
-- 
GitLab