From d0d32db17713a6538349f660da9a4e87792d4dd9 Mon Sep 17 00:00:00 2001 From: Ruben Carlo Benante Date: Tue, 7 Jul 2026 23:02:04 -0300 Subject: [PATCH] optional "Link copies to the template" toggle, default off (v0.3.1) --- Controller/RecurrenceController.php | 2 ++ Model/RecoRecoModel.php | 18 ++++++++++++++++-- Plugin.php | 2 +- Template/recurrence/edit.php | 5 +++++ VERSION | 2 +- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Controller/RecurrenceController.php b/Controller/RecurrenceController.php index 99d4b32..b36d1b3 100644 --- a/Controller/RecurrenceController.php +++ b/Controller/RecurrenceController.php @@ -52,6 +52,7 @@ class RecurrenceController extends BaseController 'recoreco_frequency' => $frequency, 'recoreco_last_day' => isset($input['recoreco_last_day']) ? 1 : 0, 'recoreco_days_before' => isset($input['recoreco_days_before']) && ctype_digit((string) $input['recoreco_days_before']) ? (int) $input['recoreco_days_before'] : 0, + 'recoreco_link_copies' => isset($input['recoreco_link_copies']) ? 1 : 0, ); // Capture the anchor (the due date at enable time) -- the drift-free pattern. The engine @@ -76,6 +77,7 @@ class RecurrenceController extends BaseController 'recoreco_frequency' => isset($meta['recoreco_frequency']) ? $meta['recoreco_frequency'] : 'monthly_day', 'recoreco_last_day' => isset($meta['recoreco_last_day']) ? (int) $meta['recoreco_last_day'] : 0, 'recoreco_days_before' => isset($meta['recoreco_days_before']) ? (int) $meta['recoreco_days_before'] : 0, + 'recoreco_link_copies' => isset($meta['recoreco_link_copies']) ? (int) $meta['recoreco_link_copies'] : 0, ); } diff --git a/Model/RecoRecoModel.php b/Model/RecoRecoModel.php index 4a60240..1c924af 100644 --- a/Model/RecoRecoModel.php +++ b/Model/RecoRecoModel.php @@ -69,6 +69,8 @@ class RecoRecoModel extends Base $lastDay = isset($meta['recoreco_last_day']) && $meta['recoreco_last_day'] == 1; $daysBefore = isset($meta['recoreco_days_before']) ? (int) $meta['recoreco_days_before'] : 0; $targetColumn = isset($meta['recoreco_target_column']) ? (int) $meta['recoreco_target_column'] : (int) $task['column_id']; + // Default off: only keep the duplicate link when explicitly turned on. + $linkCopies = isset($meta['recoreco_link_copies']) && $meta['recoreco_link_copies'] == 1; $cursor = (int) $task['date_due']; $synced = isset($meta['recoreco_synced_due']) ? (int) $meta['recoreco_synced_due'] : null; @@ -89,7 +91,7 @@ class RecoRecoModel extends Base $fireTime = $cursor - $daysBefore * 86400; while ($fireTime <= $now && $spawned < self::CATCHUP_CAP) { - $this->spawn($task, $targetColumn); + $this->spawn($task, $targetColumn, $linkCopies); $next = $this->calculator()->occurrenceFrom($anchor, $frequency, $lastDay, $cursor, false); @@ -126,7 +128,7 @@ class RecoRecoModel extends Base $this->taskMetadataModel->save($task_id, array('recoreco_synced_due' => $cursor)); } - private function spawn(array $template, $targetColumn) + private function spawn(array $template, $targetColumn, $linkCopies) { // The template's date_due is already the occurrence (setDue), so duplicate() copies it onto // the clone. duplicate() copies fields + tags + links + subtasks, but NO metadata, so the @@ -146,6 +148,18 @@ class RecoRecoModel extends Base // Reset the "[DUPLICATE]" prefix back to the source title (no events). $this->taskModificationModel->update(array('id' => $newId, 'title' => $template['title']), false); + // Kanboard's duplicate() adds an "is a duplicate of" task link between the template and the + // clone. Kept when recoreco_link_copies is on (a running count + one-click navigation to + // each copy); stripped when off (the default), to avoid piling up links on frequent + // schedules. getAll() returns the opposite task as $link['task_id'] and the row id as 'id'. + if (! $linkCopies) { + foreach ($this->taskLinkModel->getAll($newId) as $link) { + if ((int) $link['task_id'] === (int) $template['id']) { + $this->taskLinkModel->remove($link['id']); + } + } + } + // Mark the clone: white icon + cannot itself be made recurring; record its source template. $this->taskMetadataModel->save($newId, array( 'recoreco_clone' => 1, diff --git a/Plugin.php b/Plugin.php index e650928..8619016 100644 --- a/Plugin.php +++ b/Plugin.php @@ -36,7 +36,7 @@ class Plugin extends Base public function getPluginVersion() { - return '0.3.0'; + return '0.3.1'; } public function getPluginHomepage() diff --git a/Template/recurrence/edit.php b/Template/recurrence/edit.php index 6ebdf7f..e047c90 100644 --- a/Template/recurrence/edit.php +++ b/Template/recurrence/edit.php @@ -34,6 +34,11 @@ form->label(t('Create the copy this many days before the due date'), 'recoreco_days_before') ?> + form->checkbox('recoreco_link_copies', t('Link copies to the template'), 1, $values['recoreco_link_copies'] == 1) ?> +

+ +

+ modal->submitButtons() ?> diff --git a/VERSION b/VERSION index 09fa2f0..5daebf3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -RecoReco v0.3 +RecoReco v0.3.1