v1.6 duemonth/aroundmonth search keywords + auto-added month filter bookmarks

This commit is contained in:
2026-07-09 06:49:15 -03:00
parent bc266ff969
commit 4d7f88aa94
8 changed files with 211 additions and 41 deletions

View File

@@ -16,19 +16,29 @@ use Kanboard\Model\CustomFilterModel;
* MetadataModel::get() uses `?:`, and PHP treats the string "0" as falsy, so a stored "0" would
* come back as the 'default' fallback and "Always off" would never be honored.
*
* Also maintains a shared "Show all tasks" custom filter (an empty query) on every board, so there
* is always a one-click way to clear the board filter and reveal open + closed tasks.
* Also maintains shared, reserved-name custom filters on every board (v1.5 "Show all tasks", v1.6
* "Due this month" / "Around this month"), each group gated by its own config toggle.
*/
class OrganonProjectHelper extends Base
{
const EMPHASIZE_KEY = 'organon_tweaks_emphasize_duedate';
const EMPHASIZE_DEFAULT_KEY = 'organon_tweaks_emphasize_duedate_default';
// Config toggles for the auto-managed custom-filter groups.
const SHOW_ALL_FILTER_KEY = 'organon_tweaks_show_all_filter';
const MONTH_FILTERS_KEY = 'organon_tweaks_month_filters';
// The plugin RESERVES this custom-filter name: a fixed (non-translated) string so the dedup is
// stable across locales. A user's own filter with this name is absorbed into the canonical form.
const SHOW_ALL_FILTER_NAME = 'Show all tasks';
// Reserved custom-filter groups: each row is [name, query, append]. The NAME is reserved by the
// plugin (fixed, non-translated strings so dedup is stable across locales); a user's own filter
// with a reserved name is absorbed into the canonical form. "Show all tasks" is a REPLACE filter
// (append 0) so it clears; the rest are APPEND (1) so clicks stack (distinct attributes AND).
const GROUP_SHOW_ALL = array(
array('Show all tasks', '', 0),
);
const GROUP_MONTH = array(
array('Due this month', 'duemonth:this', 1),
array('Around this month', 'aroundmonth:this', 1),
);
/**
* Should the current board emphasize the due date? Board pages only (project_id in the route).
@@ -58,15 +68,17 @@ class OrganonProjectHelper extends Base
}
/**
* Ensure the board has exactly one canonical "Show all tasks" filter (empty query, shared).
* Idempotent: create it when absent, force a same-named one back to the canonical form (reserved
* name), and drop any duplicates. Called lazily on every project-header render, so it covers old
* and new boards alike. No-op without a real project and a real owner (custom_filters.user_id has
* a FK to users, so a system id like 0 would fail the insert).
* Ensure one canonical reserved custom filter on a board (shared). Idempotent: create when
* absent, force a same-named one back to the canonical form (query + shared + append) since the
* name is reserved, and drop duplicates. No-op without a real project and a real owner
* (custom_filters.user_id has a FK to users, so a system id like 0 would fail the insert).
*
* @param int $project_id
* @param int $project_id
* @param string $name
* @param string $query
* @param int $append
*/
public function ensureShowAllFilter($project_id)
public function ensureReservedFilter($project_id, $name, $query, $append)
{
$project_id = (int) $project_id;
$user_id = (int) $this->userSession->getId();
@@ -75,30 +87,32 @@ class OrganonProjectHelper extends Base
return;
}
$append = $append ? 1 : 0;
$existing = $this->db->table(CustomFilterModel::TABLE)
->eq('project_id', $project_id)
->eq('name', self::SHOW_ALL_FILTER_NAME)
->eq('name', $name)
->findAll();
if (empty($existing)) {
$this->db->table(CustomFilterModel::TABLE)->insert(array(
'filter' => '',
'filter' => $query,
'project_id' => $project_id,
'user_id' => $user_id,
'name' => self::SHOW_ALL_FILTER_NAME,
'name' => $name,
'is_shared' => 1,
'append' => 0,
'append' => $append,
));
return;
}
// Reserved name: keep one, force it to the canonical empty + shared form, drop the rest.
// Reserved name: keep one, force it to the canonical form, drop the rest.
$keep = array_shift($existing);
if ($keep['filter'] !== '' || (int) $keep['is_shared'] !== 1) {
if ($keep['filter'] !== $query || (int) $keep['is_shared'] !== 1 || (int) $keep['append'] !== $append) {
$this->db->table(CustomFilterModel::TABLE)
->eq('id', $keep['id'])
->update(array('filter' => '', 'is_shared' => 1));
->update(array('filter' => $query, 'is_shared' => 1, 'append' => $append));
}
foreach ($existing as $duplicate) {
@@ -107,23 +121,55 @@ class OrganonProjectHelper extends Base
}
/**
* Toggle turned ON: eagerly (re)create the "Show all tasks" filter on every existing board.
* ensureShowAllFilter() keeps covering boards created afterwards.
* Ensure every ENABLED group's filters on a board. Called lazily on each project-header render,
* so it covers old and new boards alike.
*
* @param int $project_id
*/
public function addShowAllFilterToAllProjects()
public function ensureBoardFilters($project_id)
{
foreach ($this->projectModel->getAll() as $project) {
$this->ensureShowAllFilter((int) $project['id']);
if ((int) $this->configModel->get(self::SHOW_ALL_FILTER_KEY, 1) === 1) {
$this->ensureGroup($project_id, self::GROUP_SHOW_ALL);
}
if ((int) $this->configModel->get(self::MONTH_FILTERS_KEY, 1) === 1) {
$this->ensureGroup($project_id, self::GROUP_MONTH);
}
}
private function ensureGroup($project_id, array $rows)
{
foreach ($rows as $row) {
$this->ensureReservedFilter($project_id, $row[0], $row[1], $row[2]);
}
}
/**
* Toggle turned OFF: remove every "Show all tasks" filter across all boards (reserved name).
* Toggle turned ON: eagerly (re)create a group's filters on every existing board.
* ensureBoardFilters() keeps covering boards created afterwards.
*
* @param array $rows
*/
public function removeAllShowAllFilters()
public function addGroupToAllProjects(array $rows)
{
$this->db->table(CustomFilterModel::TABLE)
->eq('name', self::SHOW_ALL_FILTER_NAME)
->remove();
foreach ($this->projectModel->getAll() as $project) {
$this->ensureGroup((int) $project['id'], $rows);
}
}
/**
* Toggle turned OFF: remove a group's filters across all boards (by their reserved names).
*
* @param array $rows
*/
public function removeGroup(array $rows)
{
$names = array();
foreach ($rows as $row) {
$names[] = $row[0];
}
$this->db->table(CustomFilterModel::TABLE)->in('name', $names)->remove();
}
}