Hide total in columns

This commit is contained in:
2026-07-12 08:05:14 -03:00
parent b4b7ef74d6
commit 405c7d2431
6 changed files with 142 additions and 0 deletions

59
Asset/js/relocate.js Normal file
View File

@@ -0,0 +1,59 @@
/*
* FinanceBuddy -- place the "Hide/Show column total" entry inside the native column menu.
*
* Kanboard only exposes the template:board:column:dropdown hook AFTER the column menu <ul>, and its
* dropdown JS clones just that <ul> when the menu opens. So the hook item cannot reach the menu on
* its own. column_dropdown.php renders the item hidden next to the menu; this script moves each such
* item into that column's real <ul> so it appears alongside "Hide this column", etc.
*
* BoardDragAndDrop.refresh() does $("#board-container").replaceWith(data) on every drag-and-drop and
* poll refresh, so the observer is bound to the STABLE parent of #board-container (which survives the
* swap), not to #board-container itself -- otherwise it would be left watching a detached node and
* the entry would vanish until a full page reload.
*/
(function () {
"use strict";
function relocate() {
var items = document.querySelectorAll(".financebuddy-menu-item");
for (var i = 0; i < items.length; i++) {
var li = items[i];
// Already moved into a menu list: just make sure it is visible.
if (li.closest("ul")) {
li.style.display = "";
continue;
}
// The hook renders the item as a child of the column's dropdown wrapper; its first <ul>
// is the native menu.
var menu = li.parentNode ? li.parentNode.querySelector("ul") : null;
if (menu) {
menu.appendChild(li);
li.style.display = "";
}
}
}
function init() {
var container = document.getElementById("board-container");
if (!container) {
return;
}
relocate();
if (window.MutationObserver && container.parentNode) {
new MutationObserver(relocate).observe(container.parentNode, { childList: true, subtree: true });
}
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();

View File

@@ -0,0 +1,34 @@
<?php
namespace Kanboard\Plugin\FinanceBuddy\Controller;
use Kanboard\Controller\BaseController;
use Kanboard\Core\Controller\AccessForbiddenException;
use Kanboard\Plugin\FinanceBuddy\Helper\FinanceHelper;
/**
* Toggle a board column's header total on/off from the column dropdown menu. The per-column flag
* lives in project metadata; project-manager gated (same scope as enabling FinanceBuddy). Returns
* to the board, whose reload re-renders the header with or without the total.
*/
class FinanceColumnController extends BaseController
{
public function toggleTotal()
{
$this->checkCSRFParam();
$project = $this->getProject();
if (! $this->helper->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])) {
throw new AccessForbiddenException();
}
$key = FinanceHelper::HIDE_TOTAL_PREFIX.$this->request->getIntegerParam('column_id');
// Store the literal 'on'/'off' (both non-empty) rather than 1/0, so the flag is never lost
// to PHP's empty("0") === true on the metadata save.
$hidden = $this->projectMetadataModel->get($project['id'], $key, FinanceHelper::HIDE_TOTAL_OFF) === FinanceHelper::HIDE_TOTAL_ON;
$this->projectMetadataModel->save($project['id'], array($key => $hidden ? FinanceHelper::HIDE_TOTAL_OFF : FinanceHelper::HIDE_TOTAL_ON));
$this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $project['id'])));
}
}

View File

@@ -19,6 +19,13 @@ class FinanceHelper extends Base
const INSTALLMENT_CURRENT_KEY = 'financebuddy_installment_current';
const INSTALLMENT_TOTAL_KEY = 'financebuddy_installment_total';
// Per-column opt-out of the header total. Stored per column in PROJECT metadata as
// financebuddy_hide_total_<column_id> = 'on' (hidden) or 'off' (shown, the default). Literal
// on/off, never 1/0, so the flag is never dropped by the metadata save (PHP empty("0") === true).
const HIDE_TOTAL_PREFIX = 'financebuddy_hide_total_';
const HIDE_TOTAL_ON = 'on';
const HIDE_TOTAL_OFF = 'off';
// Hidden marker present only when the task form was submitted with the finance fieldset, so
// non-finance task updates (moves, API calls) are ignored by the persistence hooks.
const FORM_MARKER = 'financebuddy_form';
@@ -110,6 +117,18 @@ class FinanceHelper extends Base
return $net;
}
/**
* Has this column's header total been hidden (per-column opt-out)?
*
* @param integer $project_id
* @param integer $column_id
* @return bool
*/
public function isTotalHidden($project_id, $column_id)
{
return $this->projectMetadataModel->get((int) $project_id, self::HIDE_TOTAL_PREFIX.(int) $column_id, self::HIDE_TOTAL_OFF) === self::HIDE_TOTAL_ON;
}
/**
* Values to prefill the task-form fields: a re-post (after a validation error) wins, then the
* stored metadata for an existing task, otherwise blanks for a new task.

View File

@@ -47,6 +47,14 @@ class Plugin extends Base
// Per-column net total (credits - debits) in the column header.
$this->template->hook->attach('template:board:column:header', 'financeBuddy:board/column_total');
// "Hide/Show column total" toggle in the column dropdown menu. The only column-menu hook
// renders after the native <ul>, so column_dropdown.php emits the item hidden and relocate.js
// moves it into the menu (same technique as BulkMoveTasks, with the stable-parent observer).
$this->template->hook->attach('template:board:column:dropdown', 'financeBuddy:board/column_dropdown');
$this->hook->on('template:layout:js', array(
'template' => 'plugins/FinanceBuddy/Asset/js/relocate.js',
));
// The same money badge at the top of the opened card (task view), under the title, so a
// card shows its money whether you are on the board or reading the card. Reuses the board
// badge template (both hooks pass $task).

View File

@@ -0,0 +1,17 @@
<?php if ($this->FinanceHelper->isEnabled($column['project_id']) && $this->user->hasProjectAccess('ProjectEditController', 'edit', $column['project_id'])): ?>
<?php /* Rendered here (outside the menu <ul>) by the only column-menu hook, then moved into the
column's real dropdown <ul> by Asset/js/relocate.js so it sits next to the native
entries. Hidden until relocated to avoid a flash in the header. */ ?>
<?php $hidden = $this->FinanceHelper->isTotalHidden($column['project_id'], $column['id']); ?>
<li class="financebuddy-menu-item" style="display: none;">
<?= $this->url->link(
$hidden
? '<i class="fa fa-eye fa-fw"></i> '.t('Show column total')
: '<i class="fa fa-eye-slash fa-fw"></i> '.t('Hide column total'),
'FinanceColumnController',
'toggleTotal',
array('plugin' => 'FinanceBuddy', 'project_id' => $column['project_id'], 'column_id' => $column['id']),
true
) ?>
</li>
<?php endif ?>

View File

@@ -7,6 +7,11 @@ if (empty($column['project_id']) || ! $this->FinanceHelper->isEnabled($column['p
return;
}
// Per-column opt-out, toggled from the column dropdown menu.
if ($this->FinanceHelper->isTotalHidden($column['project_id'], $column['id'])) {
return;
}
$net = $this->FinanceHelper->columnNet($column);
if ($net > 0) {