Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c88e52ab01 | |||
| f2f690ef98 |
@@ -25,6 +25,8 @@ class ConfigController extends BaseController
|
|||||||
'organon_tweaks_shortcut_labels' => (int) $this->configModel->get('organon_tweaks_shortcut_labels', 1),
|
'organon_tweaks_shortcut_labels' => (int) $this->configModel->get('organon_tweaks_shortcut_labels', 1),
|
||||||
'organon_tweaks_title_click_edit' => (int) $this->configModel->get('organon_tweaks_title_click_edit', 1),
|
'organon_tweaks_title_click_edit' => (int) $this->configModel->get('organon_tweaks_title_click_edit', 1),
|
||||||
'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_closes_task' => (int) $this->configModel->get('organon_tweaks_done_closes_task', 0),
|
||||||
),
|
),
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
)));
|
)));
|
||||||
@@ -45,6 +47,8 @@ class ConfigController extends BaseController
|
|||||||
$shortcutLabels = isset($values['organon_tweaks_shortcut_labels']) ? 1 : 0;
|
$shortcutLabels = isset($values['organon_tweaks_shortcut_labels']) ? 1 : 0;
|
||||||
$titleClickEdit = isset($values['organon_tweaks_title_click_edit']) ? 1 : 0;
|
$titleClickEdit = isset($values['organon_tweaks_title_click_edit']) ? 1 : 0;
|
||||||
$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;
|
||||||
|
$doneClosesTask = isset($values['organon_tweaks_done_closes_task']) ? 1 : 0;
|
||||||
|
|
||||||
if ($this->configModel->save(array(
|
if ($this->configModel->save(array(
|
||||||
'organon_tweaks_always_comment_icon' => $alwaysCommentIcon,
|
'organon_tweaks_always_comment_icon' => $alwaysCommentIcon,
|
||||||
@@ -58,6 +62,8 @@ class ConfigController extends BaseController
|
|||||||
'organon_tweaks_shortcut_labels' => $shortcutLabels,
|
'organon_tweaks_shortcut_labels' => $shortcutLabels,
|
||||||
'organon_tweaks_title_click_edit' => $titleClickEdit,
|
'organon_tweaks_title_click_edit' => $titleClickEdit,
|
||||||
'organon_tweaks_persistent_sort' => $persistentSort,
|
'organon_tweaks_persistent_sort' => $persistentSort,
|
||||||
|
'organon_tweaks_done_badge' => $doneBadge,
|
||||||
|
'organon_tweaks_done_closes_task' => $doneClosesTask,
|
||||||
))) {
|
))) {
|
||||||
$this->flash->success(t('Settings saved successfully.'));
|
$this->flash->success(t('Settings saved successfully.'));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
47
Controller/DoneController.php
Normal file
47
Controller/DoneController.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Plugin\OrganonTweaks\Controller;
|
||||||
|
|
||||||
|
use Kanboard\Controller\BaseController;
|
||||||
|
use Kanboard\Plugin\OrganonTweaks\Helper\OrganonDoneHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle a task's Done/Due badge (OrganonTweaks).
|
||||||
|
*
|
||||||
|
* One-click CSRF link from the board card face and the task view. Single source of truth per mode:
|
||||||
|
* - close-mode on: Done == closed, so this just closes/opens the task (no metadata); native
|
||||||
|
* Close/Open stay in sync automatically because the badge reads is_active.
|
||||||
|
* - close-mode off: this flips the 'organon_done' metadata marker and never touches open/closed.
|
||||||
|
* Redirects back to wherever it was clicked (board or task view).
|
||||||
|
*/
|
||||||
|
class DoneController extends BaseController
|
||||||
|
{
|
||||||
|
public function toggle()
|
||||||
|
{
|
||||||
|
$task = $this->getTask();
|
||||||
|
$this->checkCSRFParam();
|
||||||
|
|
||||||
|
$helper = new OrganonDoneHelper($this->container);
|
||||||
|
$done = $helper->isDone($task);
|
||||||
|
|
||||||
|
if ($helper->closesTask()) {
|
||||||
|
if ($done) {
|
||||||
|
$this->taskStatusModel->open($task['id']);
|
||||||
|
} else {
|
||||||
|
$this->taskStatusModel->close($task['id']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($done) {
|
||||||
|
$this->taskMetadataModel->remove($task['id'], OrganonDoneHelper::DONE_KEY);
|
||||||
|
} else {
|
||||||
|
$this->taskMetadataModel->save($task['id'], array(OrganonDoneHelper::DONE_KEY => 'on'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->request->getStringParam('from') === 'board') {
|
||||||
|
$this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $task['project_id'])), true);
|
||||||
|
} else {
|
||||||
|
$this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'])), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
50
Helper/OrganonDoneHelper.php
Normal file
50
Helper/OrganonDoneHelper.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Plugin\OrganonTweaks\Helper;
|
||||||
|
|
||||||
|
use Kanboard\Core\Base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Done/Due badge helper.
|
||||||
|
*
|
||||||
|
* "Done" has a single source of truth PER MODE (no drift with native Close/Open):
|
||||||
|
* - close-mode on ("check done also closes tasks"): Done == the task is CLOSED (is_active == 0).
|
||||||
|
* The badge reads the task's own is_active, so however a task is closed/reopened (badge, native
|
||||||
|
* sidebar, bulk, API) the badge always matches. No metadata is stored in this mode.
|
||||||
|
* - close-mode off (marker only): Done == the task metadata DONE_KEY == 'on', independent of the
|
||||||
|
* open/closed status. Stored as the non-falsy string 'on' (never '0'/'1'): MetadataModel::get()
|
||||||
|
* uses `?:` and PHP treats "0" as falsy, so a stored "0" would read back as the default.
|
||||||
|
*
|
||||||
|
* Templates cannot read models directly, so the board/task-view badge templates call isDone() here,
|
||||||
|
* passing the task array (which carries both id and is_active) so the close-mode read needs no query.
|
||||||
|
*/
|
||||||
|
class OrganonDoneHelper extends Base
|
||||||
|
{
|
||||||
|
const DONE_KEY = 'organon_done';
|
||||||
|
const CLOSES_KEY = 'organon_tweaks_done_closes_task';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this task Done? (mode-aware: closed status in close-mode, else the metadata marker)
|
||||||
|
*
|
||||||
|
* @param array $task a task array carrying 'id' and 'is_active'
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDone(array $task)
|
||||||
|
{
|
||||||
|
if ($this->closesTask()) {
|
||||||
|
return isset($task['is_active']) && (int) $task['is_active'] === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->taskMetadataModel->get((int) $task['id'], self::DONE_KEY, '') === 'on';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should toggling Done also close (and reopen) the task? Global setting, default off.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function closesTask()
|
||||||
|
{
|
||||||
|
return (int) $this->configModel->get(self::CLOSES_KEY, 0) === 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Plugin.php
14
Plugin.php
@@ -111,6 +111,16 @@ class Plugin extends Base
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tweak: a Done/Due status badge on the card face (top-right, below the header) and in the
|
||||||
|
// task view (4th column, near the due date). Two-state toggle; single source of truth per
|
||||||
|
// mode -- close-mode ON => Done == closed (reads is_active, so native Close/Open stay in
|
||||||
|
// sync); close-mode OFF => a task-metadata marker (organon_done). Server-rendered, no JS.
|
||||||
|
if ((int) $this->configModel->get('organon_tweaks_done_badge', 0) === 1) {
|
||||||
|
$this->template->hook->attach('template:board:private:task:before-title', 'organonTweaks:board/done_badge');
|
||||||
|
$this->template->hook->attach('template:task:details:fourth-column', 'organonTweaks:task/done_badge');
|
||||||
|
$this->template->hook->attach('template:layout:head', 'organonTweaks:layout/done_style');
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
// recurring filters). Ensured lazily whenever a project header renders (covers old + new
|
// recurring filters). Ensured lazily whenever a project header renders (covers old + new
|
||||||
// boards); each group is gated by its own config toggle inside
|
// boards); each group is gated by its own config toggle inside
|
||||||
@@ -141,7 +151,7 @@ class Plugin extends Base
|
|||||||
public function getHelpers()
|
public function getHelpers()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'Plugin\OrganonTweaks\Helper' => array('OrganonColumnHelper', 'OrganonProjectHelper', 'OrganonSortHelper'),
|
'Plugin\OrganonTweaks\Helper' => array('OrganonColumnHelper', 'OrganonProjectHelper', 'OrganonSortHelper', 'OrganonDoneHelper'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +172,7 @@ class Plugin extends Base
|
|||||||
|
|
||||||
public function getPluginVersion()
|
public function getPluginVersion()
|
||||||
{
|
{
|
||||||
return '1.9.1';
|
return '2.0.1';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPluginHomepage()
|
public function getPluginHomepage()
|
||||||
|
|||||||
25
README.md
25
README.md
@@ -117,6 +117,26 @@ single arrow** (up for ascending, down for descending) when it is ON.
|
|||||||
(which also hides the native sort menu). Per-column state lives in project metadata.
|
(which also hides the native sort menu). Per-column state lives in project metadata.
|
||||||
- **On by default.** Toggle it under "Settings -> Organon Tweaks".
|
- **On by default.** Toggle it under "Settings -> Organon Tweaks".
|
||||||
|
|
||||||
|
### Done/Due badge
|
||||||
|
|
||||||
|
A two-state toggle badge for marking a card done, shown on the board card face (top-right, below the
|
||||||
|
header) and on the task view (4th column, near the due date). It reads **`[ ] Due`** (dark red) while
|
||||||
|
the task is pending; one click flips it to **`[x] Done`** (light green). The card itself is not
|
||||||
|
recolored -- only the badge. The "Due" colors reuse FinanceBuddy's debit badge for consistency.
|
||||||
|
|
||||||
|
- Rendered server-side (no JavaScript) via `template:board:private:task:before-title`
|
||||||
|
(`Template/board/done_badge.php`), `template:task:details:fourth-column`
|
||||||
|
(`Template/task/done_badge.php`), and a small head `<style>` (`Template/layout/done_style.php`).
|
||||||
|
Shown only to users who may edit the task; on the board it appears on expanded (non-collapsed) cards.
|
||||||
|
- **Single source of truth, no drift with native Close/Open.** With *"Marking Done also closes the
|
||||||
|
task"* **on**, "Done" *means* the task is closed: the badge reads the task's own open/closed status,
|
||||||
|
so closing or reopening a task by any route (the badge, the native sidebar, bulk actions, the API)
|
||||||
|
always keeps the badge correct. A closed "Done" card is hidden from the board by Kanboard's default
|
||||||
|
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
|
||||||
|
(`organon_done`) that never touches the open/closed status.
|
||||||
|
- **Off by default.** Toggle it under "Settings -> Organon Tweaks".
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
Global (per Kanboard instance) and admin-only, under "Settings -> Organon Tweaks", grouped as on
|
Global (per Kanboard instance) and admin-only, under "Settings -> Organon Tweaks", grouped as on
|
||||||
@@ -143,6 +163,11 @@ the page:
|
|||||||
|
|
||||||
- **Per-column persistent sort** -- default on.
|
- **Per-column persistent sort** -- default on.
|
||||||
|
|
||||||
|
**Done badge**
|
||||||
|
|
||||||
|
- **Show a Done/Due badge on cards** -- default off.
|
||||||
|
- **Marking Done also closes the task** -- default off.
|
||||||
|
|
||||||
Standalone:
|
Standalone:
|
||||||
|
|
||||||
- **Keep the board scroll position across refreshes** -- default on.
|
- **Keep the board scroll position across refreshes** -- default on.
|
||||||
|
|||||||
23
Template/board/done_badge.php
Normal file
23
Template/board/done_badge.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Done/Due badge on the board card face. Rendered by template:board:private:task:before-title; the
|
||||||
|
* CSS in layout/done_style.php pins it to the top-right (below the header) and colors the two states.
|
||||||
|
* Only shown to users who may edit the task (a read-only viewer sees no badge). Expanded cards only
|
||||||
|
* (collapsed cards do not fire this hook).
|
||||||
|
*/
|
||||||
|
if (! $this->user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$done = $this->OrganonDoneHelper->isDone($task);
|
||||||
|
?>
|
||||||
|
<span class="organontweaks-done<?= $done ? ' is-done' : '' ?>">
|
||||||
|
<?= $this->url->link(
|
||||||
|
$done ? '<i class="fa fa-check-square"></i> '.t('Done') : '<i class="fa fa-square"></i> '.t('Due'),
|
||||||
|
'DoneController',
|
||||||
|
'toggle',
|
||||||
|
array('plugin' => 'OrganonTweaks', 'task_id' => $task['id'], 'project_id' => $task['project_id'], 'from' => 'board'),
|
||||||
|
true,
|
||||||
|
'',
|
||||||
|
$done ? t('Mark as not done') : t('Mark as done')
|
||||||
|
) ?>
|
||||||
|
</span>
|
||||||
@@ -62,6 +62,16 @@
|
|||||||
<p class="form-help"><?= t('Replaces the native column sort with a control that adds a number-aware Title sort and a "Persistent sort: ON/OFF" toggle. When ON, the column is re-sorted whenever a card is dropped in or created, so it stays sorted (a red up/down arrow marks it). OFF is the native one-shot sort.') ?></p>
|
<p class="form-help"><?= t('Replaces the native column sort with a control that adds a number-aware Title sort and a "Persistent sort: ON/OFF" toggle. When ON, the column is re-sorted whenever a card is dropped in or created, so it stays sorted (a red up/down arrow marks it). OFF is the native one-shot sort.') ?></p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend><?= t('Done badge') ?></legend>
|
||||||
|
|
||||||
|
<?= $this->form->checkbox('organon_tweaks_done_badge', t('Show a Done/Due badge on cards'), 1, isset($values['organon_tweaks_done_badge']) && $values['organon_tweaks_done_badge'] == 1) ?>
|
||||||
|
<p class="form-help"><?= t('A two-state toggle badge on the board card (top-right) and the task view (near the due date): "Due" (red) until you click it, then "Done" (green). Off by default.') ?></p>
|
||||||
|
|
||||||
|
<?= $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 Due reopens it -- native Close/Open stay in sync. When off, the badge is an independent marker that never changes the open/closed status.') ?></p>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
|
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
29
Template/layout/done_style.php
Normal file
29
Template/layout/done_style.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Done/Due badge styling (emitted into the head when the feature is enabled). NATURAL document flow --
|
||||||
|
* the badge renders above the title (board card) or as a list item (task view); no absolute
|
||||||
|
* positioning, so it adapts to any card / column / avatar / username size. Two states via .is-done:
|
||||||
|
* Due = black filled box + black text on a light red (#ef9a9a); Done = checked box, black on light
|
||||||
|
* green (#a5d6a7). Both states use black text (core's `.task-board a { color:#000 }` forces the icon
|
||||||
|
* black anyway, so the backgrounds are kept light for contrast). Colors are tunable.
|
||||||
|
*/
|
||||||
|
?>
|
||||||
|
<style>
|
||||||
|
span.organontweaks-done a {
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #ef9a9a;
|
||||||
|
color: #000;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
span.organontweaks-done.is-done a {
|
||||||
|
background: #a5d6a7;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.organontweaks-done {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 1px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
24
Template/task/done_badge.php
Normal file
24
Template/task/done_badge.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Done/Due badge in the task view, 4th column (near the due date). Rendered by
|
||||||
|
* template:task:details:fourth-column as a list item, matching the surrounding <li> fields. Same
|
||||||
|
* two-state toggle as the board badge; only shown to users who may edit the task.
|
||||||
|
*/
|
||||||
|
if (! $this->user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$done = $this->OrganonDoneHelper->isDone($task);
|
||||||
|
?>
|
||||||
|
<li>
|
||||||
|
<span class="organontweaks-done<?= $done ? ' is-done' : '' ?>">
|
||||||
|
<?= $this->url->link(
|
||||||
|
$done ? '<i class="fa fa-check-square"></i> '.t('Done') : '<i class="fa fa-square"></i> '.t('Due'),
|
||||||
|
'DoneController',
|
||||||
|
'toggle',
|
||||||
|
array('plugin' => 'OrganonTweaks', 'task_id' => $task['id'], 'project_id' => $task['project_id'], 'from' => 'task'),
|
||||||
|
true,
|
||||||
|
'',
|
||||||
|
$done ? t('Mark as not done') : t('Mark as done')
|
||||||
|
) ?>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
Reference in New Issue
Block a user