Skip to content
Snippets Groups Projects

Draft: Resolve "[TCC planning] Frontend is incredibly slow with large amounts of entries"

4 unresolved threads
Compare and
7 files
+ 302
126
Compare changes
  • Side-by-side
  • Inline
Files
7
@@ -14,7 +14,8 @@ import SubjectChip from "aleksis.apps.cursus/components/SubjectChip.vue";
disable-pagination
hide-default-footer
:headers="headers"
:items="tableItems"
:items="items"
:loading="$apollo.queries.subjects.loading"
>
<template #top>
<v-row>
@@ -55,6 +56,23 @@ import SubjectChip from "aleksis.apps.cursus/components/SubjectChip.vue";
/>
</v-col>
<v-col
cols="6"
lg="2"
class="d-flex justify-space-between flex-wrap align-center"
>
<v-switch
v-model="includeChildGroups"
inset
:label="
$t(
'lesrooster.timebound_course_config.filters.include_child_groups',
)
"
:loading="$apollo.queries.subjects.loading"
></v-switch>
</v-col>
<v-spacer />
<v-col
@@ -79,6 +97,7 @@ import SubjectChip from "aleksis.apps.cursus/components/SubjectChip.vue";
!createdCourseConfigs.length &&
!createdCourses.length
"
:loading="loading"
@click="save"
/>
</v-col>
@@ -190,6 +209,7 @@ import {
subjects,
createTimeboundCourseConfigs,
updateTimeboundCourseConfigs,
createCoursesForSchoolTerm,
} from "./timeboundCourseConfig.graphql";
import { currentValidityRange as gqlCurrentValidityRange } from "../validity_range/validityRange.graphql";
@@ -229,11 +249,14 @@ export default {
subjects: [],
editedCourseConfigs: [],
createdCourseConfigs: [],
newCourses: [],
createdCourses: [],
currentCourse: null,
currentSubject: null,
loading: false,
includeChildGroups: true,
selectedGroupHeaders: [],
items: [],
groupCombinationsSet: new Set(),
};
},
methods: {
@@ -242,15 +265,7 @@ export default {
},
getCurrentCourseConfig(course) {
if (course.lrTimeboundCourseConfigs?.length) {
let currentCourseConfigs = course.lrTimeboundCourseConfigs.filter(
(timeboundConfig) =>
timeboundConfig.validityRange.id === this.internalValidityRange.id,
);
if (currentCourseConfigs.length) {
return currentCourseConfigs[0];
} else {
return null;
}
return course.lrTimeboundCourseConfigs[0];
} else {
return null;
}
@@ -266,7 +281,7 @@ export default {
this.createdCourses.push({
subject: subject.id,
groups: JSON.parse(header.value),
name: `${header.text}-${subject.name}`,
schoolTerm: this.internalValidityRange.schoolTerm.id,
...newValue,
});
} else {
@@ -274,9 +289,7 @@ export default {
}
} else {
if (
!course.lrTimeboundCourseConfigs?.filter(
(c) => c.validityRange.id === this.internalValidityRange?.id,
).length
!course.lrTimeboundCourseConfigs?.length
) {
let existingCreatedCourseConfig = this.createdCourseConfigs.find(
(c) =>
@@ -321,7 +334,7 @@ export default {
},
{
data: this.createdCourses,
mutation: createCourses,
mutation: createCoursesForSchoolTerm,
},
]) {
if (mutationCombination.data.length) {
@@ -361,66 +374,91 @@ export default {
];
},
addCourse(subject, groups) {
let courseSubjectGroup = this.newCourses.find(
(courseSubject) => courseSubject.subject === subject,
this.$set(
this.items.find((i) => i.subject.id === subject),
groups,
[{ teachers: [], newCourse: true }],
);
if (courseSubjectGroup) {
if (courseSubjectGroup.groupCombinations) {
this.$set(courseSubjectGroup.groupCombinations, groups, [
{ teachers: [], newCourse: true },
]);
} else {
courseSubjectGroup.groupCombinations = {
[groups]: [{ teachers: [], newCourse: true }],
};
}
} else {
this.newCourses.push({
subject: subject,
groupCombinations: { [groups]: [{ teachers: [], newCourse: true }] },
},
generateTableItems(subjects) {
return subjects.map((subject) => {
let { courses, ...reducedSubject } = subject;
let groupCombinations = {};
courses.forEach((course) => {
const ownGroupIDs = course.groups.map((group) => group.id);
let groupIDs;
if (
this.includeChildGroups &&
ownGroupIDs.some((groupID) => !this.groupIDSet.has(groupID))
) {
groupIDs = JSON.stringify(
course.groups
.flatMap((group) =>
group.parentGroups.map((parentGroup) => parentGroup.id),
)
.sort(),
);
} else {
groupIDs = JSON.stringify(ownGroupIDs.sort());
}
if (!groupCombinations[groupIDs]) {
groupCombinations[groupIDs] = [];
if (course.groups.length > 1) {
this.groupCombinationsSet.add(groupIDs);
}
groupCombinations[groupIDs].push({
...course,
});
} else if (
!groupCombinations[groupIDs].some((c) => c.id === course.id)
) {
groupCombinations[groupIDs].push({
...course,
});
}
});
}
return {
subject: reducedSubject,
...Object.fromEntries(
this.groupHeaders.map((header) => [header.value, []]),
),
...groupCombinations,
};
});
},
},
computed: {
groupIDList() {
return this.selectedGroups.map((group) => group.id);
groupIDSet() {
return new Set(this.selectedGroups.map((group) => group.id));
},
subjectGroupCombinations() {
return [].concat.apply(
[],
this.items.map((subject) => Object.keys(subject.groupCombinations)),
);
groupCombinationHeaders() {
return this.subjectGroupCombinations.map((combination) => {
let parsedCombination = JSON.parse(combination);
return {
text: parsedCombination
.map(
(groupID) =>
this.selectedGroups.find((group) => group.id === groupID)
?.shortName ||
this.selectedGroups.find((group) => group.id === groupID)
?.shortName,
)
.join(", "),
value: combination,
};
});
},
groupHeaders() {
return this.selectedGroups
.map((group) => ({
text: group.shortName,
value: JSON.stringify([group.id]),
}))
.concat(
this.subjectGroupCombinations.map((combination) => {
let parsedCombination = JSON.parse(combination);
return {
text: parsedCombination
.map(
(groupID) =>
this.groups.find((group) => group.id === groupID).shortName,
)
.join(", "),
value: combination,
};
}),
)
.filter(
(obj, index, self) =>
index === self.findIndex((o) => o.value === obj.value),
);
return [...this.selectedGroupHeaders, ...this.groupCombinationHeaders];
},
headers() {
let groupHeadersWithWidth = this.groupHeaders.map((header) => ({
...header,
width: `${Math.max(95 / this.groupHeaders.length, 15)}vw`,
width: "20vw",
}));
return [
{
@@ -430,52 +468,16 @@ export default {
},
].concat(groupHeadersWithWidth);
},
items() {
return this.subjects.map((subject) => {
let groupCombinations = {};
subject.courses.forEach((course) => {
let groupIds = JSON.stringify(
course.groups.map((group) => group.id).sort(),
);
if (!groupCombinations[groupIds]) {
groupCombinations[groupIds] = [];
}
if (!groupCombinations[groupIds].find((c) => c.id === course.id)) {
groupCombinations[groupIds].push({
...course,
});
}
});
subject = {
...subject,
groupCombinations: { ...groupCombinations },
newCourses: {
...this.newCourses.find(
(courseSubject) => courseSubject.subject === subject.id,
)?.groupCombinations,
},
};
return subject;
});
subjectGroupCombinations() {
return Array.from(this.groupCombinationsSet);
},
tableItems() {
return this.items.map((subject) => {
// eslint-disable-next-line no-unused-vars
let { courses, groupCombinations, ...reducedSubject } = subject;
return {
subject: reducedSubject,
...Object.fromEntries(
this.groupHeaders.map((header) => [header.value, []]),
),
...subject.groupCombinations,
...subject.newCourses,
};
});
},
watch: {
selectedGroups(newValue) {
this.selectedGroupHeaders = newValue.map((group) => ({
text: group.shortName,
value: JSON.stringify([group.id]),
}));
},
},
apollo: {
@@ -486,27 +488,29 @@ export default {
this.internalValidityRange = data.currentValidityRange;
},
},
groups: {
query: gqlGroups,
},
groupsForPlanning: {
query: gqlGroupsForPlanning,
result({ data }) {
if (!data) return;
console.log(data.groups);
this.selectedGroups = data.groupsForPlanning;
},
},
subjects: {
query: subjects,
skip() {
return !this.groupIDList.length;
return !this.groupIDSet.size || !this.internalValidityRange || !this.persons.length;
},
variables() {
return {
groups: this.groupIDList,
groups: Array.from(this.groupIDSet),
includeChildGroups: this.includeChildGroups,
validityRange: this.internalValidityRange.id,
};
},
result({ data }) {
if (!data) return;
this.items = this.generateTableItems(data.subjects);
},
},
persons: {
query: gqlTeachers,
Loading