Skip to content
Snippets Groups Projects
Verified Commit 4d6e5409 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Merge branch '1-frontend-for-models' of...

Merge branch '1-frontend-for-models' of edugit.org:AlekSIS/onboarding/AlekSIS-App-Lesrooster into 1-frontend-for-models
parents 64395760 fcf0d1f6
No related branches found
No related tags found
1 merge request!2Resolve "Frontend for Models"
......@@ -24,7 +24,7 @@ query breakSlots($orderBy: [String], $filters: JSONString) {
}
}
mutation createBreakSlot($input: CreateBreakInput!) {
mutation createBreakSlot($input: CreateBreakSlotInput!) {
createBreakSlot(input: $input) {
item: breakSlot {
id
......@@ -90,7 +90,7 @@ mutation deleteBreakSlots($ids: [ID]!) {
}
}
mutation updateBreakSlots($input: [BatchPatchBreakInput]!) {
mutation updateBreakSlots($input: [BatchPatchBreakSlotInput]!) {
batchMutation: updateBreakSlots(input: $input) {
items: breakSlots {
id
......
......@@ -282,7 +282,12 @@ export default {
},
computed: {
slots() {
return this.items;
return this.items
?.sort(
(a,b) =>
parseInt(a.timeStart.replace(":", ""))
- parseInt(b.timeStart.replace(":", ""))
) || [];
},
columns() {
return (
......@@ -499,11 +504,12 @@ export default {
#slot-container {
display: grid;
grid-template-columns: v-bind(columns);
grid-auto-rows: 1fr auto;
grid-auto-rows: 1fr;
gap: 0.7rem;
overflow-x: scroll;
margin: -1em;
padding: 1em;
grid-auto-flow: column;
}
.min-height {
......
......@@ -39,8 +39,6 @@ export default defineComponent({
<v-card
:style="{
gridColumn: item.weekday,
gridRow:
item.model === 'Slot' ? item.period * 2 + 1 : item.periodAfter * 2,
}"
:disabled="disabled"
>
......
......@@ -13,7 +13,7 @@ export default defineComponent({
</script>
<template>
<v-chip class="text-body-1 font-weight-500 px-4 mb-1" small color="white">
<v-chip class="text-body-1 font-weight-500 px-4 mb-1" small color="white" light>
<v-icon
v-if="course.lessonsUsed === course.lessonQuota"
color="green"
......
<template>
<v-card class="d-flex justify-space-between align-center">
<v-card-title>{{ period }}</v-card-title>
<div class="ma-0 py-4">
<br><br>
</div>
<v-card-subtitle
class="ma-0 pa-4 subtitle text-right"
v-if="timeRanges.length < 2"
>
{{ getTimeRangesByWeekdaysString(timeRanges?.[0]) }}
</v-card-subtitle>
<v-menu v-if="timeRanges.length > 1" offset-x>
<template #activator="{ attrs, on }">
<v-btn icon color="info" v-bind="attrs" v-on="on">
<v-icon>$info</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item v-for="timeRange in timeRanges">
{{ getTimeRangesByWeekdaysString(timeRange) }}
</v-list-item>
</v-list>
</v-menu>
</v-card>
</template>
<script>
export default {
name: "PeriodCard",
props: {
period: {
type: Number,
required: true,
},
weekdays: {
type: Array,
required: true,
},
timeRanges: {
type: Array,
required: true,
},
},
methods: {
getOutermostItems(arr) {
const result = [];
// Convert the input array into an array of numbers
const numbers = arr.map((item) => parseInt(item.slice(2), 10));
let startIndex = 0;
for (let i = 1; i < numbers.length; i++) {
if (numbers[i] !== numbers[i - 1] + 1) {
result.push(arr.slice(startIndex, i));
startIndex = i;
}
}
// Push the last subarray
result.push(arr.slice(startIndex));
return result.map((array) =>
array.length < 3 ? array : [array[0], array[array.length - 1]],
);
},
getTimeRangesByWeekdaysString(timeRange) {
return (
(timeRange.weekdays.length === this.weekdays.length
? ""
: this.getOutermostItems(timeRange.weekdays)
.map(
(weekdays) =>
weekdays
.map((weekday) => this.$t("weekdays_short." + weekday))
.join(""), // Non-breaking hyphen (U+02011)
)
.join(", ") + ": ") +
this.$d(
new Date("1970-01-01T" + timeRange.timeStart),
"shortTime",
).replace(" ", " ") +
(timeRange.weekdays.length === this.weekdays.length ? " " : "") + // Non-breaking hyphen (U+02011)
this.$d(
new Date("1970-01-01T" + timeRange.timeEnd),
"shortTime",
).replace(" ", " ")
);
},
},
};
</script>
<style scoped>
.subtitle {
width: min-content;
}
</style>
......@@ -4,10 +4,10 @@ import {
courses,
createLesson,
deleteLesson,
gqlGroups,
lessonObjects,
moveLesson,
updateLesson,
gqlGroups,
} from "./timetableManagement.graphql";
import { gqlTeachers } from "../helper.graphql";
import { timeGrids } from "../validity_range/validityRange.graphql";
......@@ -26,10 +26,12 @@ import RoomTimeTable from "./timetables/RoomTimeTable.vue";
import LessonRatioChip from "./LessonRatioChip.vue";
import TimeGridField from "../validity_range/TimeGridField.vue";
import BlockingCard from "./BlockingCard.vue";
import PeriodCard from "./PeriodCard.vue";
export default defineComponent({
name: "TimetableManagement",
components: {
PeriodCard,
BlockingCard,
TimeGridField,
SubjectField,
......@@ -68,19 +70,19 @@ export default defineComponent({
fields: [
{
text: this.$t(
"lesrooster.timetable_management.lesson_fields.subject"
"lesrooster.timetable_management.lesson_fields.subject",
),
value: "subject",
},
{
text: this.$t(
"lesrooster.timetable_management.lesson_fields.teachers"
"lesrooster.timetable_management.lesson_fields.teachers",
),
value: "teachers",
},
{
text: this.$t(
"lesrooster.timetable_management.lesson_fields.rooms"
"lesrooster.timetable_management.lesson_fields.rooms",
),
value: "rooms",
},
......@@ -103,7 +105,7 @@ export default defineComponent({
result({ data: { groups } }) {
if (!this.selectedGroup && this.$route.params.id && this.groups) {
this.selectedGroup = this.groups.find(
(group) => group.id === this.$route.params.id
(group) => group.id === this.$route.params.id,
);
}
},
......@@ -126,20 +128,20 @@ export default defineComponent({
new Set(
items
.filter((slot) => slot.model === "Slot")
.map((slot) => slot.weekday)
)
.map((slot) => slot.weekday),
),
);
this.periods = Array.from(
new Set(
items
.filter((slot) => slot.model === "Slot")
.map((slot) => slot.period)
)
.map((slot) => slot.period),
),
);
this.slotsByPeriods = this.periods.map((period) => ({
period: period,
slots: items.filter(
(slot) => slot.model === "Slot" && slot.period === period
(slot) => slot.model === "Slot" && slot.period === period,
),
}));
},
......@@ -174,7 +176,7 @@ export default defineComponent({
data && data.courses
? data.courses.reduce(
(accumulator, course) => accumulator + course.lessonQuota,
0
0,
)
: 0;
},
......@@ -270,14 +272,14 @@ export default defineComponent({
(slot) =>
slot.model === "Slot" &&
slot.weekday === weekday &&
slot.period === period
slot.period === period,
).length === 0
? {
x: indexX + 1,
y: indexY + 1,
}
: undefined
)
: undefined,
),
)
.flat()
.filter((val) => val !== undefined);
......@@ -288,10 +290,10 @@ export default defineComponent({
{
lessonsUsed: Object.values(this.lessonsUsed).reduce(
(a, b) => a + b,
0
0,
),
lessonQuota: this.lessonQuotaTotal,
}
},
);
},
},
......@@ -307,7 +309,7 @@ export default defineComponent({
this.$setToolBarTitle(
this.$t("lesrooster.timetable_management.for_group", {
group: this.selectedGroup.name,
})
}),
);
this.$apollo.queries.courses.refetch();
this.$apollo.queries.lessonObjects.refetch();
......@@ -318,12 +320,12 @@ export default defineComponent({
let newStartSlotId = this.slots.filter(
(slot) =>
slot.period === this.periods[eventData.y - 1] &&
slot.weekday === this.weekdays[eventData.x - 1]
slot.weekday === this.weekdays[eventData.x - 1],
);
let newEndSlotId = this.slots.filter(
(slot) =>
slot.period === this.periods[eventData.y + eventData.h - 2] &&
slot.weekday === this.weekdays[eventData.x + eventData.w - 2]
slot.weekday === this.weekdays[eventData.x + eventData.w - 2],
);
let newStartSlot, newEndSlot;
......@@ -367,12 +369,12 @@ export default defineComponent({
data: {
updateLesson: { lesson },
},
}
},
) {
let query = {
...that.$apollo.queries.lessonObjects.options,
variables: JSON.parse(
that.$apollo.queries.lessonObjects.previousVariablesJson
that.$apollo.queries.lessonObjects.previousVariablesJson,
),
};
// Read the data from cache for query
......@@ -384,7 +386,7 @@ export default defineComponent({
}
const index = storedData.lessonObjects.findIndex(
(lessonObject) => lessonObject.id === lesson.id
(lessonObject) => lessonObject.id === lesson.id,
);
storedData.lessonObjects[index].slotStart = lesson.slotStart;
storedData.lessonObjects[index].slotEnd = lesson.slotEnd;
......@@ -395,12 +397,12 @@ export default defineComponent({
})
.then((data) => {
this.$toastSuccess(
"lesrooster.timetable_management.snacks.lesson_move.success"
"lesrooster.timetable_management.snacks.lesson_move.success",
);
})
.catch((error) => {
this.$toastError(
"lesrooster.timetable_management.snacks.lesson_move.error"
"lesrooster.timetable_management.snacks.lesson_move.error",
);
});
} else if (eventData.originGridId === "courses") {
......@@ -452,12 +454,12 @@ export default defineComponent({
data: {
createLesson: { lesson },
},
}
},
) {
let query = {
...that.$apollo.queries.lessonObjects.options,
variables: JSON.parse(
that.$apollo.queries.lessonObjects.previousVariablesJson
that.$apollo.queries.lessonObjects.previousVariablesJson,
),
};
// Read the data from cache for query
......@@ -476,12 +478,12 @@ export default defineComponent({
})
.then((data) => {
this.$toastSuccess(
"lesrooster.timetable_management.snacks.lesson_create.success"
"lesrooster.timetable_management.snacks.lesson_create.success",
);
})
.catch((error) => {
this.$toastError(
"lesrooster.timetable_management.snacks.lesson_create.error"
"lesrooster.timetable_management.snacks.lesson_create.error",
);
});
}
......@@ -501,12 +503,12 @@ export default defineComponent({
.filter(
(slot) =>
slot.weekday === lesson.slotEnd.weekday &&
slot.period > lesson.slotEnd.period
slot.period > lesson.slotEnd.period,
)
.reduce(
(prev, current) =>
prev && prev.period > current.period ? current : prev || current,
null
null,
);
return !!nextSlot;
......@@ -540,12 +542,12 @@ export default defineComponent({
data: {
updateLesson: { lesson },
},
}
},
) {
let query = {
...that.$apollo.queries.lessonObjects.options,
variables: JSON.parse(
that.$apollo.queries.lessonObjects.previousVariablesJson
that.$apollo.queries.lessonObjects.previousVariablesJson,
),
};
// Read the data from cache for query
......@@ -557,7 +559,7 @@ export default defineComponent({
}
const index = storedData.lessonObjects.findIndex(
(lessonObject) => lessonObject.id === lesson.id
(lessonObject) => lessonObject.id === lesson.id,
);
storedData.lessonObjects[index].slotStart = lesson.slotStart;
storedData.lessonObjects[index].slotEnd = lesson.slotEnd;
......@@ -568,12 +570,12 @@ export default defineComponent({
})
.then((data) => {
this.$toastSuccess(
"lesrooster.timetable_management.snacks.lesson_change_length.success"
"lesrooster.timetable_management.snacks.lesson_change_length.success",
);
})
.catch((error) => {
this.$toastError(
"lesrooster.timetable_management.snacks.lesson_change_length.error"
"lesrooster.timetable_management.snacks.lesson_change_length.error",
);
});
},
......@@ -583,10 +585,10 @@ export default defineComponent({
.filter(
(slot) =>
slot.weekday === lesson.slotEnd.weekday &&
slot.period > lesson.slotEnd.period
slot.period > lesson.slotEnd.period,
)
.reduce((prev, current) =>
prev.period < current.period ? prev : current
prev.period < current.period ? prev : current,
);
this.changeLessonSlots(lesson, lesson.slotStart, slotEnd);
......@@ -597,10 +599,10 @@ export default defineComponent({
.filter(
(slot) =>
slot.weekday === lesson.slotEnd.weekday &&
slot.period < lesson.slotEnd.period
slot.period < lesson.slotEnd.period,
)
.reduce((prev, current) =>
prev.period > current.period ? prev : current
prev.period > current.period ? prev : current,
);
this.changeLessonSlots(lesson, lesson.slotStart, slotEnd);
......@@ -632,17 +634,17 @@ export default defineComponent({
return [
{
header: this.$t(
"lesrooster.timebound_course_config.subject_teachers"
"lesrooster.timebound_course_config.subject_teachers",
),
},
...this.persons.filter((person) =>
subjectTeachers.find((teacher) => teacher.id === person.id)
subjectTeachers.find((teacher) => teacher.id === person.id),
),
{ divider: true },
{ header: this.$t("lesrooster.timebound_course_config.all_teachers") },
...this.persons.filter(
(person) =>
!subjectTeachers.find((teacher) => teacher.id === person.id)
!subjectTeachers.find((teacher) => teacher.id === person.id),
),
];
},
......@@ -650,7 +652,7 @@ export default defineComponent({
const query = {
...this.$apollo.queries.lessonObjects.options,
variables: JSON.parse(
this.$apollo.queries.lessonObjects.previousVariablesJson
this.$apollo.queries.lessonObjects.previousVariablesJson,
),
};
// Read the data from cache for query
......@@ -662,7 +664,7 @@ export default defineComponent({
}
const index = storedData.lessonObjects.findIndex(
(lessonObject) => lessonObject.id === lesson.id
(lessonObject) => lessonObject.id === lesson.id,
);
storedData.lessonObjects[index].subject = lesson.subject;
storedData.lessonObjects[index].teachers = lesson.teachers;
......@@ -673,12 +675,12 @@ export default defineComponent({
},
handleLessonEditSave() {
this.$toastSuccess(
"lesrooster.timetable_management.snacks.lesson_edit.success"
"lesrooster.timetable_management.snacks.lesson_edit.success",
);
},
handleLessonEditError() {
this.$toastError(
"lesrooster.timetable_management.snacks.lesson_edit.error"
"lesrooster.timetable_management.snacks.lesson_edit.error",
);
},
lessonEditGetPatchData(lesson) {
......@@ -700,17 +702,17 @@ export default defineComponent({
item.data.subject?.teachers?.some(
(teacher) =>
teacher.fullName?.toLowerCase().includes(search) ||
teacher.shortName?.toLowerCase().includes(search)
teacher.shortName?.toLowerCase().includes(search),
) ||
item.data.teachers?.some(
(teacher) =>
teacher.fullName?.toLowerCase().includes(search) ||
teacher.shortName?.toLowerCase().includes(search)
teacher.shortName?.toLowerCase().includes(search),
) ||
item.data.groups?.some(
(group) =>
group.name?.toLowerCase().includes(search) ||
group.shortName?.toLowerCase().includes(search)
group.shortName?.toLowerCase().includes(search),
)
);
});
......@@ -720,7 +722,7 @@ export default defineComponent({
if (item.group === null) {
return this.$t(
"lesrooster.validity_range.time_grid.repr.generic",
item.validityRange
item.validityRange,
);
}
return this.$t("lesrooster.validity_range.time_grid.repr.default", [
......@@ -737,8 +739,8 @@ export default defineComponent({
self.findIndex(
(timeRange) =>
timeRange.timeStart === value.timeStart &&
timeRange.timeEnd === value.timeEnd
)
timeRange.timeEnd === value.timeEnd,
),
)
.map((timeRange) => ({
...timeRange,
......@@ -746,50 +748,11 @@ export default defineComponent({
.filter(
(slot) =>
slot.timeStart === timeRange.timeStart &&
slot.timeEnd === timeRange.timeEnd
slot.timeEnd === timeRange.timeEnd,
)
.map((slot) => slot.weekday),
}));
},
getOutermostItems(arr) {
const result = [];
// Convert the input array into an array of numbers
const numbers = arr.map((item) => parseInt(item.slice(2), 10));
let startIndex = 0;
for (let i = 1; i < numbers.length; i++) {
if (numbers[i] !== numbers[i - 1] + 1) {
result.push(arr.slice(startIndex, i));
startIndex = i;
}
}
// Push the last subarray
result.push(arr.slice(startIndex));
return result.map((array) =>
array.length < 3 ? array : [array[0], array[array.length - 1]]
);
},
getTimeRangesByWeekdaysString(timeRange) {
return (
(timeRange.weekdays.length === this.weekdays.length
? ""
: this.getOutermostItems(timeRange.weekdays)
.map(
(weekdays) =>
weekdays
.map((weekday) => this.$t("weekdays_short." + weekday))
.join("") // Non-breaking hyphen (U+02011)
)
.join(", ") + ": ") +
this.$d(new Date("1970-01-01T" + timeRange.timeStart), "shortTime") +
" " +
this.$d(new Date("1970-01-01T" + timeRange.timeEnd), "shortTime")
);
},
},
});
</script>
......@@ -839,6 +802,7 @@ export default defineComponent({
<secondary-action-button
i18n-key="actions.copy_last_configuration"
block
disabled
/>
</v-col>
......@@ -855,24 +819,19 @@ export default defineComponent({
</v-card>
</div>
<div id="periods">
<v-card
<period-card
v-for="(period, index) in periods"
:key="period"
class="d-flex justify-center align-center"
>
<v-card-title>{{ period }}</v-card-title>
<v-card-subtitle class="ma-0 pa-4">
<div
v-for="timeRange in timeRangesByWeekdays(
slotsByPeriods.find(
(periodWithSlots) => periodWithSlots.period === period
)
)"
>
{{ getTimeRangesByWeekdaysString(timeRange) }}
</div>
</v-card-subtitle>
</v-card>
:period="period"
:weekdays="weekdays"
:time-ranges="
timeRangesByWeekdays(
slotsByPeriods.find(
(periodWithSlots) => periodWithSlots.period === period,
),
)
"
/>
</div>
<drag-grid
:cols="weekdays.length"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment