* Calendar: ask user to apply changes in series master to already created exceptions

This commit is contained in:
ralf 2024-06-29 16:40:32 +02:00
parent cbd2e4c695
commit 7ccd1e4cf2
5 changed files with 97 additions and 21 deletions

View File

@ -864,11 +864,12 @@ class calendar_uiforms extends calendar_ui
unset($event['edit_single']); // if we further edit it, it's just a single event
unset($preserv['edit_single']);
}
else // conflict or error, we need to reset everything to the state befor we tried to save it
else // conflict or error, we need to reset everything to the state before we tried to save it
{
$event['id'] = $event['reference'];
$event['reference'] = $event['recurrence'] = 0;
$event['uid'] = $content['uid'];
$preserv['apply_to_future_exceptions'] = $content['apply_to_future_exceptions'] ?? null;
}
$update_type = 'edit';
}
@ -933,8 +934,15 @@ class calendar_uiforms extends calendar_ui
if (is_array($conflicts))
{
$event['button_was'] = $button; // remember for ignore
$preserv['apply_changes_to_exceptions'] = $content['apply_changes_to_exceptions'] ?? null;
$preserv['no_notifications'] = $content['no_notifications'] ?? null;
return $this->conflicts($event,$conflicts,$preserv);
}
// check if we should apply the changes to the exceptions
if (!empty($content['apply_changes_to_exceptions']))
{
$this->apply_changes_to_exceptions($event, $messages, !empty($content['no_notifications']));
}
// Event spans multiple days, need an edit to make sure they all get updated
// We could check old date, as removing from days could still be an update
@ -1201,7 +1209,7 @@ class calendar_uiforms extends calendar_ui
$event['recurrence'] = $preserv['recurrence'] = $preserv['actual_date'];
$event['start'] = $preserv['edit_single'] = $preserv['actual_date'];
$event['recur_type'] = MCAL_RECUR_NONE;
foreach(array('recur_enddate','recur_interval','recur_exception','recur_data') as $name)
foreach(array('recur_enddate','recur_interval','recur_exception','recur_data', 'recur_rdates') as $name)
{
unset($event[$name]);
}
@ -1947,6 +1955,9 @@ class calendar_uiforms extends calendar_ui
//Disable videoconference if the module is not enabled
$etpl->disableElement('videoconference', calendar_hooks::isVideoconferenceDisabled());
$content['future_exceptions'] = !empty($content['id']) && !empty($content['recur_type']) &&
$this->bo->search(['start' => Api\DateTime::to('now', 'ts')], 'cal_reference='.(int)$content['id']);
// non_interactive==true from $_GET calls immediate save action without displaying the edit form
if(isset($_GET['non_interactive']) && (bool)$_GET['non_interactive'] === true)
{
@ -1962,6 +1973,66 @@ class calendar_uiforms extends calendar_ui
}
}
/**
* Apply given data of event-master to future exceptions
*
* @param array $master
* @param ?array $messages on return error-messages
* @param ?bool $skip_notifications
* @return void
*/
protected function apply_changes_to_exceptions(array $master, ?array $messages=null, ?bool $skip_notifications=null)
{
foreach($this->bo->search([
'start' => Api\DateTime::to('now', 'ts')
], 'cal_reference='.(int)$master['id']) as $event)
{
$changes = 0;
foreach($master as $name => $value)
{
switch($name)
{
case 'title';
case 'description':
case 'location':
case 'cat_id':
case 'priority':
if ($event[$name] != $value)
{
$event[$name] = $value;
$changes++;
}
break;
case 'participants':
// only add new participants, leave status of current participants alone
foreach($value as $uid => $status)
{
if (!isset($event['participants'][$uid]))
{
$event['participants'][$uid] = $status;
$changes++;
}
}
unset($event['participant_status']);
break;
default:
if ($name[0] === '#' && $event[$name] != $value)
{
$event[$name] = $value;
$changes++;
}
break;
}
if ($changes)
{
$this->bo->update($event, true, true, false, true, $messages, $skip_notifications);
}
}
}
}
/**
* Set up the participants for display in edit dialog
*

View File

@ -2261,14 +2261,14 @@ export class CalendarApp extends EgwApp
*/
move_edit_series(_DOM,_button)
{
var content : any = this.et2.getArrayMgr('content').data;
var start_date = this.et2.getValueById('start');
var end_date = this.et2.getValueById('end');
var whole_day = <et2_checkbox> this.et2.getWidgetById('whole_day');
var duration = ''+this.et2.getValueById('duration');
var is_whole_day = whole_day && whole_day.get_value() == whole_day.options.selected_value;
var button = _button;
var that = this;
const content : any = this.et2.getArrayMgr('content').data;
const start_date = this.et2.getValueById('start');
const end_date = this.et2.getValueById('end');
const whole_day = <et2_checkbox> this.et2.getWidgetById('whole_day');
const duration = ''+this.et2.getValueById('duration');
const is_whole_day = whole_day && whole_day.get_value() == whole_day.options.selected_value;
const button = _button;
const that = this;
let instance_date_regex = window.location.search.match(/date=(\d{4}-\d{2}-\d{2}(?:.+Z)?)/);
let instance_date;
@ -2278,15 +2278,13 @@ export class CalendarApp extends EgwApp
instance_date.setUTCMinutes(instance_date.getUTCMinutes() +instance_date.getTimezoneOffset());
}
if (typeof content != 'undefined' && content.id != null &&
typeof content.recur_type != 'undefined' && content.recur_type != null && content.recur_type != 0
)
typeof content.recur_type != 'undefined' && content.recur_type != null && content.recur_type != 0)
{
if (content.start != start_date ||
content.whole_day != is_whole_day ||
(duration && ''+content.duration != duration ||
// End date might ignore seconds, and be 59 seconds off for all day events
!duration && Math.abs(new Date(end_date) - new Date(content.end)) > 60000)
)
!duration && Math.abs(new Date(end_date) - new Date(content.end)) > 60000))
{
et2_calendar_event.series_split_prompt(
content, instance_date, function(_button_id)
@ -2294,20 +2292,22 @@ export class CalendarApp extends EgwApp
if(_button_id == Et2Dialog.OK_BUTTON)
{
that.et2.getInstanceManager().submit(button);
}
}
);
return false;
}
else
// check if we have future exceptions and changes with might be applied to them too
if (content.future_exceptions)
{
return true;
Et2Dialog.show_dialog((_button) => {
this.et2.setValueById('apply_changes_to_exceptions', _button == Et2Dialog.YES_BUTTON);
this.et2.getInstanceManager().submit(button);
}, 'Otherwise, changes to the title, description, ... or new participants will not be transferred to exceptions that have already been created.', 'Apply changes to (future) exceptions too?', undefined, Et2Dialog.BUTTONS_YES_NO, Et2Dialog.QUESTION_MESSAGE);
return false;
}
}
else
{
return true;
}
return true;
}
/**

View File

@ -61,6 +61,7 @@ allows to edit the event again calendar de Erlaubt den Termin erneut zu bearbeit
always calendar de Immer
always use full edit dialog calendar de Immer das komplette Bearbeiten-Fenster verwenden
always use the full edit dialog, not this little dialog calendar de Verwende immer das komplette Bearbeiten-Fenster, anstatt dem verkürzten Dialog.
apply changes to (future) exceptions too? calendar de Änderungen auch auf (zukünftige) Ausnahmen anwenden?
apply the action on the whole query, not only the shown events calendar de Befehl auf die gesamte Abfrage anwenden, NICHT nur auf die angezeigten Termine.
apply the changes calendar de Übernimmt die Änderungen
appointment settings calendar de Einstellungen der Terminverwaltung
@ -449,6 +450,7 @@ only used for first viewing of calendar, afterwards last selected view is used.
open todo's: calendar de Unerledigte Aufgaben:
optional calendar de Optional
organizer calendar de Organisator
otherwise, changes to the title, description, ... or new participants will not be transferred to exceptions that have already been created. calendar de Andernfalls werden Änderungen im Titel, in der Beschreibung, ... oder neue Teilnehmer nicht auf bereits erstellte Ausnahmen übertragen.
output unit calendar de Ausgabeeinheit
overlap holiday calendar de Überlappender Feiertag
owner too calendar de Auch Besitzer

View File

@ -61,6 +61,7 @@ allows to edit the event again calendar en Allows to edit the event again
always calendar en Always
always use full edit dialog calendar en Always use full edit dialog
always use the full edit dialog, not this little dialog calendar en Always use the full edit dialog, not this little dialog
apply changes to (future) exceptions too? calendar en Apply changes to (future) exceptions too?
apply the action on the whole query, not only the shown events calendar en Apply the action on the whole query, NOT only the shown events.
apply the changes calendar en Apply the changes
appointment settings calendar en Appointment settings
@ -449,6 +450,7 @@ only used for first viewing of calendar, afterwards last selected view is used.
open todo's: calendar en Open ToDo's:
optional calendar en Optional
organizer calendar en Organizer
otherwise, changes to the title, description, ... or new participants will not be transferred to exceptions that have already been created. calendar en Otherwise, changes to the title, description, ... or new participants will not be transferred to exceptions that have already been created.
output unit calendar en Output unit
overlap holiday calendar en Overlap holiday
owner too calendar en Owner too

View File

@ -268,6 +268,7 @@
<et2-button statustext="Find free timeslots where the selected participants are available for the given timespan" label="Freetime search" id="freetime" onclick="app.calendar.freetime_search" image="timesheet" span="all" noSubmit="true"></et2-button>
<et2-button align="right" statustext="Delete this event" label="Delete" id="button[delete]" onclick="app.calendar.delete_btn(widget,$cont[query_delete_exceptions]);" image="delete"></et2-button>
<et2-textbox type="hidden" id="delete_exceptions"></et2-textbox>
<et2-textbox type="hidden" id="apply_changes_to_exceptions"></et2-textbox>
</et2-hbox>
</template>
</overlay>