From 57d358c504e05403a8a695c1fa3da57ac89ba5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Romain=20D=C3=A9nari=C3=A9?= Date: Wed, 21 Oct 2026 17:07:10 +0200 Subject: [PATCH] feat: Show a single planned call people already joined as in progress in the video list EXO-91106 A started call of a single event makes it live whatever its date; an occurrence of a series still holds its call only once it has begun or starts within 15 minutes. A live meeting joined ahead of its slot shows no elapsed time before its start. --- .../vue-apps/VisioDrawer/components/VisioCard.vue | 6 +++++- .../main/webapp/vue-apps/VisioDrawer/js/VisioMerge.js | 10 ++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/webapp/src/main/webapp/vue-apps/VisioDrawer/components/VisioCard.vue b/webapp/src/main/webapp/vue-apps/VisioDrawer/components/VisioCard.vue index 0fb3c841b..83292759c 100644 --- a/webapp/src/main/webapp/vue-apps/VisioDrawer/components/VisioCard.vue +++ b/webapp/src/main/webapp/vue-apps/VisioDrawer/components/VisioCard.vue @@ -523,7 +523,11 @@ export default { || this.$t('visio.drawer.dayTimeRange', {0: formatDay(this.entry.start), 1: range}); }, showProgress() { - return this.entry.state === LIVE && !!this.entry.start; + // A meeting people joined ahead of its slot is live before its start: + // there is no elapsed time to show yet. Only a slot is compared with this + // browser's clock; a call without one starts at the server's. + return this.entry.state === LIVE && !!this.entry.start + && (!this.entry.end || this.entry.start.getTime() <= this.now.getTime()); }, /** * How long the meeting has been running. diff --git a/webapp/src/main/webapp/vue-apps/VisioDrawer/js/VisioMerge.js b/webapp/src/main/webapp/vue-apps/VisioDrawer/js/VisioMerge.js index ba23705f1..9339f63a5 100644 --- a/webapp/src/main/webapp/vue-apps/VisioDrawer/js/VisioMerge.js +++ b/webapp/src/main/webapp/vue-apps/VisioDrawer/js/VisioMerge.js @@ -54,7 +54,7 @@ const STATE_STARTED = 'started'; *

* The same window decides which occurrence of a series a running call is held * in, so the two answers cannot disagree: what the drawer calls live is what it - * lets you join. + * lets you join. A single event is not bound by it once its call is started. */ export const JOIN_AHEAD_MS = 15 * 60 * 1000; @@ -86,6 +86,9 @@ export function normalizeEvent(event) { key: `event-${eventId}-${occurrenceId}`, eventId: eventId, occurrenceId: occurrenceId, + // An occurrence of a series comes either computed (an occurrence, no id) or + // as an exceptional occurrence with an id of its own and its parent. + recurrent: !!(event.occurrence || event.parent || event.parentId || event.recurrence), title: event.summary || '', start: start, end: end, @@ -284,6 +287,9 @@ function isStarted(callId, startedIds) { * claiming it would announce next week's meeting as happening now, which is the * whole point of the attribution. *

+ * A single event has no other date to be confused with: its started call is its + * meeting, live however early people joined it. + *

* The past side needs no bound of its own: the drawer reads only PAST_WINDOW_MS * back, so an occurrence old enough to be a stale claim is never fetched. * @@ -292,7 +298,7 @@ function isStarted(callId, startedIds) { * @returns {boolean} true when the occurrence may hold the call */ function canHoldCall(event, nowTime) { - return event.start.getTime() - nowTime <= JOIN_AHEAD_MS; + return !event.recurrent || event.start.getTime() - nowTime <= JOIN_AHEAD_MS; } /**