diff --git a/calendar/inc/class.calendar_rrule.inc.php b/calendar/inc/class.calendar_rrule.inc.php
index a0179cde11..a9d15e4d77 100644
--- a/calendar/inc/class.calendar_rrule.inc.php
+++ b/calendar/inc/class.calendar_rrule.inc.php
@@ -699,7 +699,7 @@ class calendar_rrule implements Iterator
case self::RDATE:
$str_extra = array_map(static function (DateTime $rdate)
{
- return Api\DateTime::server2user($rdate, '');
+ return str_replace(',', '', Api\DateTime::server2user($rdate, ''));
}, $this->rdates);
break;
}
@@ -719,6 +719,13 @@ class calendar_rrule implements Iterator
{
$str_extra[] = $this->time->getTimezone()->getName();
}
+ if ($this->exceptions_objs)
+ {
+ $str_extra[] = lang('Exceptions').': '.implode(', ', array_map(static function (DateTime $exdate)
+ {
+ return str_replace(',', '', Api\DateTime::server2user($exdate, ''));
+ }, $this->exceptions_objs));
+ }
if(count($str_extra))
{
$str .= ' ('.implode(', ',$str_extra).')';
diff --git a/calendar/inc/class.calendar_uiforms.inc.php b/calendar/inc/class.calendar_uiforms.inc.php
index 54acedeb04..c664c85727 100644
--- a/calendar/inc/class.calendar_uiforms.inc.php
+++ b/calendar/inc/class.calendar_uiforms.inc.php
@@ -2338,6 +2338,19 @@ class calendar_uiforms extends calendar_ui
$readonlys['button[reject]'] = $readonlys['button[cancel]'] = true;
}
}
+ $all_participants = ($event['participants'] ?? []) + ($existing_event['participants'] ?? []);
+ $event['participantChanges'] = array_map(function($uid, $status) use ($existing_event, $event) {
+ return [
+ 'changed' => !isset($event['participants'][$uid]) ? 'meetingRequestParticipantDeleted' :
+ (!isset($existing_event['participants'][$uid]) ? 'meetingRequestChanged' :
+ ($status !== $existing_event['participants'][$uid] ? 'meetingRequestChangedStatus' : '')),
+ 'label' => $this->bo->participant_name($uid),
+ 'status' => lang($this->bo->verbose_status[calendar_so::split_status($status, $quantity, $role)]),
+ 'role' => $role === 'REQ-PARTICIPANT' ? '' : lang($this->bo->roles[$role] ??
+ (substr($role,0,6) === 'X-CAT-' && ($cat_id = (int)substr($role,6)) > 0 ?
+ $GLOBALS['egw']->categories->id2name($cat_id) : str_replace('X-','',$role))),
+ ];
+ }, array_keys($all_participants), $all_participants);
break;
case 'cancel':
// first participant is the (external) organizer (our iCal parser adds owner first!)
@@ -2369,6 +2382,7 @@ class calendar_uiforms extends calendar_ui
}
//error_log(__METHOD__."(...) parsed as ".array2string($event));
$event['recure'] = $this->bo->recure2string($master ?? null ?: $event);
+ if (!empty($master)) unset($event['changed']['recure']);
$event['all_participants'] = implode(",\n",$this->bo->participants($event, true));
// EGroupware event has been deleted, don't let user resurrect it by accepting again
diff --git a/calendar/templates/default/meeting.xet b/calendar/templates/default/meeting.xet
index 6154e17767..6ff8511598 100644
--- a/calendar/templates/default/meeting.xet
+++ b/calendar/templates/default/meeting.xet
@@ -78,7 +78,7 @@
-
+
@@ -110,8 +110,21 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -163,10 +176,17 @@
.meetingWarning tr.row td {
font-size: 120% !important;
}
- .meetingRequestError, .meetingRequestChanged {
+ .meetingRequestError, .meetingRequestChanged, .meetingRequestChangedStatus et2-description[id$=status\]], .meetingRequestParticipantDeleted {
font-style: italic;
color: red;
}
+ #calendar-meeting table.et2_grid.meetingRequestParticipants td {
+ padding: 0 !important;
+ padding-left: 0 !important;
+ }
+ .meetingRequestParticipantDeleted {
+ text-decoration: line-through;
+ }
\ No newline at end of file