diff --git a/public/js/components/Calendar/Base/Grid/Line.js b/public/js/components/Calendar/Base/Grid/Line.js
index 501faed6d..705de0eb2 100644
--- a/public/js/components/Calendar/Base/Grid/Line.js
+++ b/public/js/components/Calendar/Base/Grid/Line.js
@@ -60,6 +60,7 @@ export default {
template: /* html */`
@@ -71,7 +72,7 @@ export 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 */ `
- `
-}
+ `,
+};
diff --git a/public/js/components/Tempus/Tempus.js b/public/js/components/Tempus/Tempus.js
index 7d9978be5..ec68b4cca 100644
--- a/public/js/components/Tempus/Tempus.js
+++ b/public/js/components/Tempus/Tempus.js
@@ -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");
diff --git a/tests/cypress/.env.example b/tests/cypress/.env.example
index afe039acb..bf3302947 100644
--- a/tests/cypress/.env.example
+++ b/tests/cypress/.env.example
@@ -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
diff --git a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.course-picker.cy.js b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.course-picker.cy.js
index 2d6bbb597..7d967d1a0 100644
--- a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.course-picker.cy.js
+++ b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.course-picker.cy.js
@@ -81,7 +81,9 @@ context("Tempus course picker tests", () => {
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
-
+
+ cy.wait(1000);
+
cy.get("@initialEventCount").then((initialEventCount) => {
tempusPage
.getCalendarEvents()
diff --git a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.events.cy.js b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.events.cy.js
index c616b3aa5..cae3fe3df 100644
--- a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.events.cy.js
+++ b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.events.cy.js
@@ -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
diff --git a/tests/cypress/cypress/support/pages/tempus.po.js b/tests/cypress/cypress/support/pages/tempus.po.js
index baf3519a0..37050f39a 100644
--- a/tests/cypress/cypress/support/pages/tempus.po.js
+++ b/tests/cypress/cypress/support/pages/tempus.po.js
@@ -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 = {}) => {