Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ca57a4044e |
@@ -27,6 +27,7 @@ class ConfigController extends BaseController
|
|||||||
'organon_tweaks_persistent_sort' => (int) $this->configModel->get('organon_tweaks_persistent_sort', 1),
|
'organon_tweaks_persistent_sort' => (int) $this->configModel->get('organon_tweaks_persistent_sort', 1),
|
||||||
'organon_tweaks_done_badge' => (int) $this->configModel->get('organon_tweaks_done_badge', 0),
|
'organon_tweaks_done_badge' => (int) $this->configModel->get('organon_tweaks_done_badge', 0),
|
||||||
'organon_tweaks_done_closes_task' => (int) $this->configModel->get('organon_tweaks_done_closes_task', 0),
|
'organon_tweaks_done_closes_task' => (int) $this->configModel->get('organon_tweaks_done_closes_task', 0),
|
||||||
|
'organon_tweaks_done_autosubtasks' => (int) $this->configModel->get('organon_tweaks_done_autosubtasks', 0),
|
||||||
),
|
),
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
)));
|
)));
|
||||||
@@ -49,6 +50,7 @@ class ConfigController extends BaseController
|
|||||||
$persistentSort = isset($values['organon_tweaks_persistent_sort']) ? 1 : 0;
|
$persistentSort = isset($values['organon_tweaks_persistent_sort']) ? 1 : 0;
|
||||||
$doneBadge = isset($values['organon_tweaks_done_badge']) ? 1 : 0;
|
$doneBadge = isset($values['organon_tweaks_done_badge']) ? 1 : 0;
|
||||||
$doneClosesTask = isset($values['organon_tweaks_done_closes_task']) ? 1 : 0;
|
$doneClosesTask = isset($values['organon_tweaks_done_closes_task']) ? 1 : 0;
|
||||||
|
$doneAutoSubtasks = isset($values['organon_tweaks_done_autosubtasks']) ? 1 : 0;
|
||||||
|
|
||||||
if ($this->configModel->save(array(
|
if ($this->configModel->save(array(
|
||||||
'organon_tweaks_always_comment_icon' => $alwaysCommentIcon,
|
'organon_tweaks_always_comment_icon' => $alwaysCommentIcon,
|
||||||
@@ -64,6 +66,7 @@ class ConfigController extends BaseController
|
|||||||
'organon_tweaks_persistent_sort' => $persistentSort,
|
'organon_tweaks_persistent_sort' => $persistentSort,
|
||||||
'organon_tweaks_done_badge' => $doneBadge,
|
'organon_tweaks_done_badge' => $doneBadge,
|
||||||
'organon_tweaks_done_closes_task' => $doneClosesTask,
|
'organon_tweaks_done_closes_task' => $doneClosesTask,
|
||||||
|
'organon_tweaks_done_autosubtasks' => $doneAutoSubtasks,
|
||||||
))) {
|
))) {
|
||||||
$this->flash->success(t('Settings saved successfully.'));
|
$this->flash->success(t('Settings saved successfully.'));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace Kanboard\Plugin\OrganonTweaks\Helper;
|
namespace Kanboard\Plugin\OrganonTweaks\Helper;
|
||||||
|
|
||||||
use Kanboard\Core\Base;
|
use Kanboard\Core\Base;
|
||||||
|
use Kanboard\Model\SubtaskModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Done/Todo badge helper.
|
* Done/Todo badge helper.
|
||||||
@@ -22,6 +23,8 @@ class OrganonDoneHelper extends Base
|
|||||||
{
|
{
|
||||||
const DONE_KEY = 'organon_done';
|
const DONE_KEY = 'organon_done';
|
||||||
const CLOSES_KEY = 'organon_tweaks_done_closes_task';
|
const CLOSES_KEY = 'organon_tweaks_done_closes_task';
|
||||||
|
const AUTOSUB_KEY = 'organon_tweaks_done_autosubtasks';
|
||||||
|
const ALLDONE_KEY = 'organon_subtasks_alldone';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this task Done? (mode-aware: closed status in close-mode, else the metadata marker)
|
* Is this task Done? (mode-aware: closed status in close-mode, else the metadata marker)
|
||||||
@@ -47,4 +50,63 @@ class OrganonDoneHelper extends Base
|
|||||||
{
|
{
|
||||||
return (int) $this->configModel->get(self::CLOSES_KEY, 0) === 1;
|
return (int) $this->configModel->get(self::CLOSES_KEY, 0) === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a task Done in the current mode. Idempotent -- a no-op if it is already Done. Close-mode
|
||||||
|
* closes the task; marker-mode sets the DONE_KEY metadata.
|
||||||
|
*
|
||||||
|
* @param int $task_id
|
||||||
|
*/
|
||||||
|
public function markDone($task_id)
|
||||||
|
{
|
||||||
|
$task = $this->taskFinderModel->getById((int) $task_id);
|
||||||
|
|
||||||
|
if (empty($task) || $this->isDone($task)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->closesTask()) {
|
||||||
|
$this->taskStatusModel->close((int) $task_id);
|
||||||
|
} else {
|
||||||
|
$this->taskMetadataModel->save((int) $task_id, array(self::DONE_KEY => 'on'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recompute whether the task's subtasks are ALL done and, only on the up-transition
|
||||||
|
* (was-not-all-done -> now-all-done), auto-mark the task Done. The last-seen all-done state is kept
|
||||||
|
* in ALLDONE_KEY ('on'/'off') to detect that edge -- so a manual unmark is honored (nothing
|
||||||
|
* re-fires) and title edits / refreshes never re-mark. Never auto-unmarks.
|
||||||
|
*
|
||||||
|
* @param int $task_id
|
||||||
|
* @param int $exclude_id a subtask id to exclude from the counts (the row being deleted --
|
||||||
|
* EVENT_DELETE fires BEFORE the row is removed, so it still counts)
|
||||||
|
*/
|
||||||
|
public function syncSubtasksDone($task_id, $exclude_id = 0)
|
||||||
|
{
|
||||||
|
$task_id = (int) $task_id;
|
||||||
|
$exclude_id = (int) $exclude_id;
|
||||||
|
|
||||||
|
$totalQuery = $this->db->table(SubtaskModel::TABLE)->eq('task_id', $task_id);
|
||||||
|
$doneQuery = $this->db->table(SubtaskModel::TABLE)->eq('task_id', $task_id)->eq('status', SubtaskModel::STATUS_DONE);
|
||||||
|
|
||||||
|
if ($exclude_id > 0) {
|
||||||
|
$totalQuery->neq('id', $exclude_id);
|
||||||
|
$doneQuery->neq('id', $exclude_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = $totalQuery->count();
|
||||||
|
$done = $doneQuery->count();
|
||||||
|
$allDone = $total > 0 && $done === $total;
|
||||||
|
$prev = $this->taskMetadataModel->get($task_id, self::ALLDONE_KEY, 'off') === 'on';
|
||||||
|
|
||||||
|
// Save the new state BEFORE marking: in close-mode markDone() -> close() -> closeAll() re-fires
|
||||||
|
// subtask events into this method; with the marker already 'on', that re-entry sees no
|
||||||
|
// transition and is a no-op (no loop).
|
||||||
|
$this->taskMetadataModel->save($task_id, array(self::ALLDONE_KEY => $allDone ? 'on' : 'off'));
|
||||||
|
|
||||||
|
if ($allDone && ! $prev) {
|
||||||
|
$this->markDone($task_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
Plugin.php
25
Plugin.php
@@ -3,6 +3,7 @@
|
|||||||
namespace Kanboard\Plugin\OrganonTweaks;
|
namespace Kanboard\Plugin\OrganonTweaks;
|
||||||
|
|
||||||
use Kanboard\Core\Plugin\Base;
|
use Kanboard\Core\Plugin\Base;
|
||||||
|
use Kanboard\Model\SubtaskModel;
|
||||||
use Kanboard\Model\TaskModel;
|
use Kanboard\Model\TaskModel;
|
||||||
|
|
||||||
class Plugin extends Base
|
class Plugin extends Base
|
||||||
@@ -122,6 +123,28 @@ class Plugin extends Base
|
|||||||
// Bulk "Mark all as Done/Todo" entry in the column header dropdown (moved into the native
|
// Bulk "Mark all as Done/Todo" entry in the column header dropdown (moved into the native
|
||||||
// menu by relocate.js). Opens a two-button modal that confirms + picks the direction.
|
// menu by relocate.js). Opens a two-button modal that confirms + picks the direction.
|
||||||
$this->template->hook->attach('template:board:column:dropdown', 'organonTweaks:board/mark_all_item');
|
$this->template->hook->attach('template:board:column:dropdown', 'organonTweaks:board/mark_all_item');
|
||||||
|
|
||||||
|
// Sub-tweak (opt-in): auto-mark a card Done when its LAST subtask is completed. On every
|
||||||
|
// subtask change, recompute all-done and mark Done only on the up-transition
|
||||||
|
// (state-comparison in the helper), so a manual unmark is honored -- nothing re-fires.
|
||||||
|
// Dispatcher direct (the plugin on() wrapper drops the event). DELETE fires before the row
|
||||||
|
// is removed, so its id is excluded from the recount.
|
||||||
|
if ((int) $this->configModel->get('organon_tweaks_done_autosubtasks', 0) === 1) {
|
||||||
|
$container = $this->container;
|
||||||
|
$sync = function ($task_id, $exclude_id = 0) use ($container) {
|
||||||
|
$helper = new \Kanboard\Plugin\OrganonTweaks\Helper\OrganonDoneHelper($container);
|
||||||
|
$helper->syncSubtasksDone((int) $task_id, (int) $exclude_id);
|
||||||
|
};
|
||||||
|
$this->dispatcher->addListener(SubtaskModel::EVENT_UPDATE, function ($event) use ($sync) {
|
||||||
|
$sync($event['subtask']['task_id']);
|
||||||
|
});
|
||||||
|
$this->dispatcher->addListener(SubtaskModel::EVENT_CREATE, function ($event) use ($sync) {
|
||||||
|
$sync($event['subtask']['task_id']);
|
||||||
|
});
|
||||||
|
$this->dispatcher->addListener(SubtaskModel::EVENT_DELETE, function ($event) use ($sync) {
|
||||||
|
$sync($event['subtask']['task_id'], $event['subtask']['id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-managed shared custom filters (v1.5 "Show all tasks", v1.6 month filters, v1.7
|
// Auto-managed shared custom filters (v1.5 "Show all tasks", v1.6 month filters, v1.7
|
||||||
@@ -175,7 +198,7 @@ class Plugin extends Base
|
|||||||
|
|
||||||
public function getPluginVersion()
|
public function getPluginVersion()
|
||||||
{
|
{
|
||||||
return '2.1.3';
|
return '2.2.0';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPluginHomepage()
|
public function getPluginHomepage()
|
||||||
|
|||||||
@@ -142,6 +142,12 @@ recolored -- only the badge.
|
|||||||
open-only filter, but reappears if you clear the filter (or use the "Board: show all tasks" filter).
|
open-only filter, but reappears if you clear the filter (or use the "Board: show all tasks" filter).
|
||||||
- With that option **off**, the badge is an independent marker stored in task metadata
|
- With that option **off**, the badge is an independent marker stored in task metadata
|
||||||
(`organon_done`) that never touches the open/closed status.
|
(`organon_done`) that never touches the open/closed status.
|
||||||
|
- **Auto-mark on subtasks (opt-in).** When every subtask on a card is completed, the badge flips to
|
||||||
|
Done automatically (honoring the mode above -- marker or close). It only nudges at the moment the
|
||||||
|
last subtask completes: recomputing all-done on each subtask change and acting only on the
|
||||||
|
not-all-done -> all-done transition, so if you then set the badge back to Todo it is respected (the
|
||||||
|
subtasks stay done -- the description may hold unfinished business). It never auto-reverts to Todo.
|
||||||
|
Off by default; enable it in the Done badge settings.
|
||||||
- **Bulk per-column action.** The board column header dropdown gains a **Mark all as Done/Todo** entry
|
- **Bulk per-column action.** The board column header dropdown gains a **Mark all as Done/Todo** entry
|
||||||
(`Template/board/mark_all_item.php`, moved into the menu by `relocate.js`). It opens a single modal
|
(`Template/board/mark_all_item.php`, moved into the menu by `relocate.js`). It opens a single modal
|
||||||
that both confirms and picks the direction -- **Mark all Done** or **Mark all Todo** -- then sets
|
that both confirms and picks the direction -- **Mark all Done** or **Mark all Todo** -- then sets
|
||||||
|
|||||||
@@ -70,6 +70,9 @@
|
|||||||
|
|
||||||
<?= $this->form->checkbox('organon_tweaks_done_closes_task', t('Marking Done also closes the task'), 1, isset($values['organon_tweaks_done_closes_task']) && $values['organon_tweaks_done_closes_task'] == 1) ?>
|
<?= $this->form->checkbox('organon_tweaks_done_closes_task', t('Marking Done also closes the task'), 1, isset($values['organon_tweaks_done_closes_task']) && $values['organon_tweaks_done_closes_task'] == 1) ?>
|
||||||
<p class="form-help"><?= t('When on, "Done" means the task is closed (so it leaves the board unless you clear the status filter), and clicking Todo reopens it -- native Close/Open stay in sync. When off, the badge is an independent marker that never changes the open/closed status.') ?></p>
|
<p class="form-help"><?= t('When on, "Done" means the task is closed (so it leaves the board unless you clear the status filter), and clicking Todo reopens it -- native Close/Open stay in sync. When off, the badge is an independent marker that never changes the open/closed status.') ?></p>
|
||||||
|
|
||||||
|
<?= $this->form->checkbox('organon_tweaks_done_autosubtasks', t('Auto-mark Done when the last subtask is completed'), 1, isset($values['organon_tweaks_done_autosubtasks']) && $values['organon_tweaks_done_autosubtasks'] == 1) ?>
|
||||||
|
<p class="form-help"><?= t('When every subtask on a card is done, flip the badge to Done automatically (honoring the mode above). It only nudges at that moment -- if you then set it back to Todo, that is respected (the subtasks stay done).') ?></p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
|
|||||||
Reference in New Issue
Block a user