WIP: fixing issues found with cypress tests

This commit is contained in:
Ivymaster
2026-06-24 16:35:07 +02:00
parent 2630a1190b
commit af7ca6b524
7 changed files with 255 additions and 234 deletions
@@ -60,6 +60,7 @@ export default {
template: /* html */`
<div
class="fhc-calendar-base-grid-line"
:data-day="date.toISODate()"
style="position:relative;display:grid;grid-auto-flow:dense"
:style="'grid-template-' + axisRow + 's:subgrid'"
>
@@ -71,7 +72,7 @@ export default {
></line-background>
<line-event
v-for="(event, i) in eventsWithRowInfo"
:key="event.orig.eindeutige_gruppen_id || i"
:key="event.orig.kalender_id || i"
:style="'grid-' + axisRow + ': ' + event.rows.join('/')"
:event="event"
@resize-start="$emit('resize-start', $event)"
+193 -182
View File
@@ -1,201 +1,212 @@
import FhcCalendar from "./Base.js";
import { useEventLoader } from '../../composables/EventLoader.js';
import ModeWeek from './Mode/Week.js';
import ModeMonth from './Mode/Month.js';
import ModeTable from './Mode/Table.js';
import ApiKalender from '../../api/factory/tempus/kalender.js';
import draggable from '../../directives/draggable.js';
import { useEventLoader } from "../../composables/EventLoader.js";
import ModeWeek from "./Mode/Week.js";
import ModeMonth from "./Mode/Month.js";
import ModeTable from "./Mode/Table.js";
import ApiKalender from "../../api/factory/tempus/kalender.js";
import draggable from "../../directives/draggable.js";
export default {
name: "CalendarTempus",
components: {
FhcCalendar
},
inject: {
renderers: {from: 'renderers'},
appConfig: {
from: 'appConfig',
default: {
visible_status: 'all'
}
}
},
directives: {
draggable,
},
props: {
timezone: {
type: String,
required: true
},
date: {
type: [Date, String, Number, luxon.DateTime],
default: luxon.DateTime.local()
},
mode: {
type: String,
default: 'Week'
},
getPromiseFunc: {
type: Function,
required: true
},
parkedEvents: {
type: Object,
default: () => new Set()
},
visibleLecturers: {
type: Array,
default: null
},
extraBackgrounds: {
type: Array,
default: () => []
},
visibleStatus: {
type: Array,
default: () => ['all']
},
},
emits: [
"update:date",
"update:mode",
"update:range",
"drop",
"resize"
],
name: "CalendarTempus",
components: {
FhcCalendar,
},
inject: {
renderers: { from: "renderers" },
appConfig: {
from: "appConfig",
default: {
visible_status: "all",
},
},
},
directives: {
draggable,
},
props: {
timezone: {
type: String,
required: true,
},
date: {
type: [Date, String, Number, luxon.DateTime],
default: luxon.DateTime.local(),
},
mode: {
type: String,
default: "Week",
},
getPromiseFunc: {
type: Function,
required: true,
},
parkedEvents: {
type: Object,
default: () => new Set(),
},
visibleLecturers: {
type: Array,
default: null,
},
extraBackgrounds: {
type: Array,
default: () => [],
},
visibleStatus: {
type: Array,
default: () => ["all"],
},
},
emits: ["update:date", "update:mode", "update:range", "drop", "resize"],
data() {
return {
modes: {
week: Vue.markRaw(ModeWeek),
month: Vue.markRaw(ModeMonth),
tableList: Vue.markRaw(ModeTable),
},
modeOptions: {
day: {
emptyMessage: Vue.computed(() => this.$p.t('lehre/noLvFound')),
emptyMessageDetails: Vue.computed(() => this.$p.t('lehre/noLvFound'))
},
week: {
collapseEmptyDays: false
}
},
currentMode: this.mode,
teachingunits: null,
hoursplan: null,
showRaster: true,
};
},
computed: {
backgrounds() {
let now = luxon.DateTime.now().setZone(this.timezone);
data() {
return {
modes: {
week: Vue.markRaw(ModeWeek),
month: Vue.markRaw(ModeMonth),
tableList: Vue.markRaw(ModeTable),
},
modeOptions: {
day: {
emptyMessage: Vue.computed(() => this.$p.t("lehre/noLvFound")),
emptyMessageDetails: Vue.computed(() => this.$p.t("lehre/noLvFound")),
},
week: {
collapseEmptyDays: false,
},
},
currentMode: this.mode,
teachingunits: null,
hoursplan: null,
showRaster: true,
};
},
computed: {
backgrounds() {
let now = luxon.DateTime.now().setZone(this.timezone);
let past = [];
if (this.mode == 'Month')
{
past = [{
class: 'background-past',
end: now.startOf('day')
}];
}
else
{
past = [{
class: 'background-past',
end: now,
label: now.startOf('minute').toISOTime({ suppressSeconds: true, includeOffset: false })
}];
}
let past = [];
if (this.mode == "Month") {
past = [
{
class: "background-past",
end: now.startOf("day"),
},
];
} else {
past = [
{
class: "background-past",
end: now,
label: now
.startOf("minute")
.toISOTime({ suppressSeconds: true, includeOffset: false }),
},
];
}
return [
...past,
...(this.extraBackgrounds || [])
];
},
visibleEvents()
{
let list = this.events;
return [...past, ...(this.extraBackgrounds || [])];
},
visibleEvents() {
let list = this.events;
if (Array.isArray(this.visibleLecturers))
{
const visibleLectures = new Set(this.visibleLecturers);
if (Array.isArray(this.visibleLecturers)) {
const visibleLectures = new Set(this.visibleLecturers);
list = list.filter(event => {
if (!event.lektor?.length)
return true;
return event.lektor.some(lektor => visibleLectures.has(lektor.mitarbeiter_uid));
});
}
list = list.filter((event) => {
if (!event.lektor?.length) return true;
return event.lektor.some((lektor) =>
visibleLectures.has(lektor.mitarbeiter_uid),
);
});
}
if (!this.visibleStatus.length || this.visibleStatus.includes('all'))
return list;
if (!this.visibleStatus.length || this.visibleStatus.includes("all"))
return list;
return list.filter(event => this.visibleStatus.includes(event.status_kurzbz));
},
},
methods: {
eventStyle(event) {
if (!event.farbe)
return undefined;
return '--event-bg:#' + event.farbe;
},
updateRange(rangeInterval) {
this.rangeInterval = rangeInterval;
this.$emit('update:range', rangeInterval);
},
ondrop(payload){
this.$emit('drop', payload);
},
onresize(payload){
this.$emit('resize', payload);
},
resetEventLoader() {
this.reset();
},
return list.filter((event) =>
this.visibleStatus.includes(event.status_kurzbz),
);
},
},
methods: {
eventStyle(event) {
if (!event.farbe) return undefined;
return "--event-bg:#" + event.farbe;
},
updateRange(rangeInterval) {
this.rangeInterval = rangeInterval;
this.$emit("update:range", rangeInterval);
},
ondrop(payload) {
this.$emit("drop", payload);
},
onresize(payload) {
this.$emit("resize", payload);
},
resetEventLoader() {
this.reset();
},
clearOutCalendarEventEmphasis() {
this.$refs.calendar.$el
.querySelectorAll(
".fhc-calendar-base-grid .fhc-calendar-base-grid-line-event",
)
.forEach((el) => {
const spinner = el.querySelector(".spinner-overlay");
if (spinner) {
spinner.remove();
}
},
setup(props, context) {
const rangeInterval = Vue.ref(null);
el.classList.remove(
"updating-event",
"updated-event",
"updated-event-long",
"deemphasized-event",
"deemphasized-event-long",
);
});
},
},
setup(props, context) {
const rangeInterval = Vue.ref(null);
const { events, lv, reset } = useEventLoader(rangeInterval, props.getPromiseFunc);
const { events, lv, reset } = useEventLoader(
rangeInterval,
props.getPromiseFunc,
);
Vue.watch(lv, newValue => {
context.emit('update:lv', newValue);
});
Vue.watch(lv, (newValue) => {
context.emit("update:lv", newValue);
});
return {
rangeInterval,
events,
lv,
reset
};
},
return {
rangeInterval,
events,
lv,
reset,
};
},
created() {
this.$api
.call(ApiKalender.getStunden())
.then(res => {
return this.teachingunits = res.data.map(el => ({
id: el.stunde,
start: el.beginn,
end: el.ende
}));
});
created() {
this.$api.call(ApiKalender.getStunden()).then((res) => {
return (this.teachingunits = res.data.map((el) => ({
id: el.stunde,
start: el.beginn,
end: el.ende,
})));
});
this.$api
.call(ApiKalender.getCalendarHours())
.then(res => {
this.hoursplan = {
start: res.data.start,
end: res.data.end
};
});
},
template: /* html */`
this.$api.call(ApiKalender.getCalendarHours()).then((res) => {
this.hoursplan = {
start: res.data.start,
end: res.data.end,
};
});
},
template: /* html */ `
<fhc-calendar
ref="calendar"
class="fhc-calendar-lvplan"
@@ -265,5 +276,5 @@ export default {
</div>
</div>
</template>
</fhc-calendar>`
}
</fhc-calendar>`,
};
+48 -44
View File
@@ -491,7 +491,15 @@ export default {
};
},
_updateKalenderEvent(obj, startDT, endDT, start_time, end_time, onSuccess) {
_updateKalenderEvent(
obj,
startDT,
endDT,
start_time,
end_time,
onSuccess,
onError,
) {
const origStart = luxon.DateTime.fromISO(obj.orig.isostart);
const origEnd = luxon.DateTime.fromISO(obj.orig.isoend);
@@ -517,6 +525,11 @@ export default {
this.$refs.calendar.$refs.calendar.$refs.mode.$refs.view.$refs.grid.disableAutoScroll();
this.currentlyUpdatedEvent = obj.orig;
}
})
.catch((error) => {
if (onError) {
onError(error);
}
});
},
@@ -526,14 +539,14 @@ export default {
return;
const { item, start, end } = payload;
const obj = item[0];
if (!obj?.orig?.kalender_id)
return alert("Kein gültiges Kalender-Event zum Resizen");
if (!obj?.orig?.kalender_id) return;
const dates = this._parseDates(start, end);
if (!dates) return;
if (
luxon.DateTime.fromISO(obj.orig.isostart).toMillis() === dates.startDT.toMillis() &&
luxon.DateTime.fromISO(obj.orig.isostart).toMillis() ===
dates.startDT.toMillis() &&
luxon.DateTime.fromISO(obj.orig.isoend).toMillis() ===
dates.endDT.toMillis()
)
@@ -554,6 +567,10 @@ export default {
() => {
this.$refs.calendar.resetEventLoader();
},
() => {
this.$refs.calendar.clearOutCalendarEventEmphasis();
this.$refs.calendar.resetEventLoader();
},
);
},
@@ -571,7 +588,8 @@ export default {
if (!dates) return;
if (
luxon.DateTime.fromISO(obj.orig.isostart).toMillis() === dates.startDT.toMillis() &&
luxon.DateTime.fromISO(obj.orig.isostart).toMillis() ===
dates.startDT.toMillis() &&
luxon.DateTime.fromISO(obj.orig.isoend).toMillis() ===
dates.endDT.toMillis()
)
@@ -617,6 +635,16 @@ export default {
this.$refs.calendar.resetEventLoader();
this.bcc.postMessage("dropped");
},
() => {
this.$refs.calendar.clearOutCalendarEventEmphasis();
this.updateKalenderEventElementDisplay(
obj.orig.kalender_id,
luxon.DateTime.fromISO(obj.orig.isostart),
luxon.DateTime.fromISO(obj.orig.isoend)
);
this.$refs.calendar.clearOutCalendarEventEmphasis();
this.$refs.calendar.resetEventLoader();
},
);
} else {
alert("Unbekannter Drop-Typ: " + obj.type);
@@ -886,29 +914,7 @@ export default {
scrollToAndEmphasizeUpdatedEvent() {
if (!this.currentlyUpdatedEvent) return;
document
.querySelectorAll(".fhc-calendar-base-grid .part-body")
.forEach((el) => {
el.classList.remove("deemphasized-event", "deemphasized-event-long");
});
document
.querySelectorAll(
".fhc-calendar-base-grid .fhc-calendar-base-grid-line-event",
)
.forEach((el) => {
const spinner = el.querySelector(".spinner-overlay");
if (spinner) {
spinner.remove();
}
el.classList.remove(
"updating-event",
"updated-event",
"updated-event-long",
"deemphasized-event",
"deemphasized-event-long",
);
});
this.$refs.calendar.clearOutCalendarEventEmphasis();
setTimeout(() => {
const eventEl = document.querySelector(
@@ -958,34 +964,32 @@ export default {
el.classList.add(deemphasizedUpdateClassName);
}
});
document
.querySelectorAll(".fhc-calendar-base-grid .part-body")
.forEach((el) => {
if (el !== eventEl) {
el.classList.add(deemphasizedUpdateClassName);
}
});
}, timeout);
this.currentlyUpdatedEvent = null;
}, 100);
},
updateKalenderEventElementDisplay(calendarId, startDT, endDT) {
if (!calendarId) return alert("Kein gültiges Kalender-Event zum Resizen");
if (!calendarId) return;
let newPotentialStart =
startDT.diff(luxon.DateTime.fromISO("2026-06-22T00:00")).toMillis() ??
1;
let newPotentialEnd = endDT
.diff(luxon.DateTime.fromISO("2026-06-22T00:00"))
.toMillis();
let startOfDay = startDT.startOf("day");
let newPotentialStart = startDT.diff(startOfDay).toMillis() ?? 1;
let newPotentialEnd = endDT.diff(startOfDay).toMillis();
let element = document.querySelector(`[data-id="event-${calendarId}"]`);
if (!element) return alert("Kein gültiges Kalender-Event zum Resizen");
if (!element) return;
const calendarView = element.closest(".fhc-calendar-mode-week-view");
const targetGridLine = calendarView?.querySelector(
`.fhc-calendar-base-grid-line[data-day="${startOfDay.toISODate()}"]`,
);
if (!targetGridLine)
return alert("Kein gültiger Kalendertag zum Verschieben gefunden");
setTimeout(() => {
element.style.gridRowEnd = "t_" + newPotentialEnd;
targetGridLine.appendChild(element);
element.style.gridRowStart = "t_" + newPotentialStart;
element.style.gridRowEnd = "t_" + newPotentialEnd;
}, 100);
const outerDiv = document.createElement("div");
+3 -3
View File
@@ -1,4 +1,4 @@
BASE_URL=https://demo.dev.technikum-wien.at/demoanon
USER_NAME=demoadmin
USER_PASSWORD=Demo
LOGIN_AS_USER=demoadmin
USER_NAME=testUser
USER_PASSWORD=testPassword
LOGIN_AS_USER=testUser
@@ -81,7 +81,9 @@ context("Tempus course picker tests", () => {
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
cy.wait(1000);
cy.get("@initialEventCount").then((initialEventCount) => {
tempusPage
.getCalendarEvents()
@@ -55,7 +55,7 @@ context("Tempus event mutation tests", () => {
.getCalendarEventById(eventId)
.should("be.visible")
.rightclick();
tempusPage.getEventContextMenuOption("Raumauswahl").click();
tempusPage.getEventContextMenuOption("Raumauswahl").click({ force: true });
waitForOk("@fetchRoomSuggestions");
tempusPage
@@ -86,6 +86,8 @@ context("Tempus event mutation tests", () => {
tempusPage.waitForCalendarToFinishLoading();
cy.get("@newRoom").then((newRoom) => {
console.log(eventId)
console.log(newRoom)
cy.get("@updatedEventId").then((updatedEventId) => {
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
@@ -131,7 +133,7 @@ context("Tempus event mutation tests", () => {
.scrollIntoView()
.should("be.visible")
.rightclick();
tempusPage.getEventContextMenuOption("Raumauswahl").click();
tempusPage.getEventContextMenuOption("Raumauswahl").click({ force: true });
waitForOk("@fetchRoomSuggestions");
tempusPage
@@ -287,7 +287,7 @@ class TempusPage {
.contains(".bootstrap-modal.show .modal-title", "Raumauswahl")
.closest(".bootstrap-modal.show");
getRaumauswahlRoomOptions = () =>
this.getRaumauswahlModal().find(".list-group-item");
this.getRaumauswahlModal().find(".list-group-item span");
getResourcesModal = () =>
cy
.get("[data-cy='resourcesAssignmentModal']")
@@ -378,6 +378,7 @@ class TempusPage {
setCurrentSemester = () => {
this.getSemesterSetterButton().click();
waitForOk("@getCurrentSemester");
};
dropEventOnCalendarPart = (eventId, partIndex, options = {}) => {