Tasksmobile 26.900.0: новый чек-лист в приложении, фильтр на телефоне и кеш счётчиков «Сроков»
В tasksmobile 26.900.0 (сборка от 29 июля 2026 года) мобильный чек-лист задачи переписан, доска «Сроки» начала кешировать счётчики стадий, а приложение научилось добавлять наблюдателя по ссылке. Код интеграторов это задевает, только если он сам вызывает мобильные экшены модуля или подключает его JS-расширения. Пользователи заметят, что фильтр чек-листа приложение теперь запоминает на телефоне, а счётчики «Сроков» отстают до двух минут.
Новое
Чек-лист перешёл на tasks.v2
Изменения мобильный чек-лист теперь отправляет в tasks.v2.CheckList.save, complete, renew, collapse и expand, у шаблонов в tasks.v2.Template.CheckList.*. В 26.800.0 он сохранял через tasks.checklist.checklist.save. Загружает чек-лист новый экшен tasksmobile.Checklist.get. Он принимает entityId и entityType (task или template), понимает старый параметр taskId и перед выдачей проверяет право на чтение задачи или шаблона. Серверные экшены чек-листа мы разбирали в tasks 26.400.0–26.500.100.
Наблюдатель по ссылке
Ссылку на задачу с хвостом ?chatAction=addObserver&entityId=<userId> приложение обрабатывает само и добавляет пользователя в наблюдатели через tasks.V2.Task.Access.addObserver. Исход показывается тостом: no_permission, already_observer, user_inactive, not_allowed_by_policy или no_request. Последний в русской локализации звучит «Запрос доступа больше неактуален», так что ссылка работает в паре с запросом доступа к задаче.
Фильтр чек-листа запоминается на телефоне
Фильтры «Скрыть выполненные» и «Показать только мои» приложение теперь хранит в Application.storage под ключом tasks.checklist.filter.<userId>. По комментарию в коде, с вебом и другими устройствами они не синхронизируются. В 26.800.0 карточка задачи всегда открывала чек-лист с выключенным «Скрыть выполненные», а переключатель писал в веб-опцию task_options_checklist_show_completed значение с обратным смыслом, и включённый на телефоне фильтр сохранялся как «показывать выполненные». В 26.900.0 приложение эту опцию не трогает.
Экшен tasksmobile.Checklist.getShowCompleted, который читал опцию, удалён. Приложение его не вызывало и в 26.800.0.
Счётчики «Сроков» теперь в кеше
Доска «Сроки» хранит числа на стадиях в кеше, у каждого пользователя свой. В модуле впервые появился default_option.php с двумя опциями: deadline_counters_cache_enabled (по умолчанию Y) и deadline_counters_cache_ttl (120 секунд, значение обрезается до 0...300, ноль выключает кеш).
Кеш сбрасывает трейт DeadlineCountersResetTrait. Он помечен @internal, но сам приём пригодится в своём модуле. Трейт переопределяет processAfterAction() контроллера и после любого экшена, которого нет в списке читающих, чистит кеш текущего пользователя. Перечислены именно чтения, потому что лишний сброс стоит одного пересчёта, а пропущенный оставит неверные цифры на весь TTL. Ошибки кеша при сбросе трейт глушит, так как изменение к этому моменту уже сохранено. В примере ниже тот же приём собран в базовый контроллер, наследнику остаётся перечислить чтения:
<?php
declare(strict_types=1);
namespace Vendor\Board\Infrastructure\Controller;
use Bitrix\Main\Data\Cache;
use Bitrix\Main\Engine\Action;
use Bitrix\Main\Engine\Controller;
abstract class BoardController extends Controller
{
/** @return string[] экшены, после которых счётчики доски остаются верными */
abstract protected function getReadActionNames(): array;
protected function processAfterAction(Action $action, $result)
{
// движок находит экшен без учёта регистра, сравниваем так же
$reads = array_map('mb_strtolower', $this->getReadActionNames());
if (!in_array(mb_strtolower($action->getName()), $reads, true)) {
$this->dropCountersCache();
}
return parent::processAfterAction($action, $result);
}
private function dropCountersCache(): void
{
$userId = (int)$this->getCurrentUser()?->getId();
if ($userId <= 0) {
return;
}
try {
// тот же каталог, куда читающие экшены кладут счётчики пользователя
Cache::createInstance(['actual_data' => true])
->cleanDir('/vendor.board/counters/' . $userId);
} catch (\Throwable) {
// изменение уже сохранено, цифры доживут до конца TTL
}
}
}
// в своём файле Card.php
final class Card extends BoardController
{
protected function getReadActionNames(): array
{
return ['list', 'get'];
}
// listAction(), getAction(), moveAction(), deleteAction() ...
}
Параметр actual_data взят из модуля. Он нужен на Redis, Memcache и APCu, если в секции cache файла .settings.php стоит 'actual_data' => false. Эта настройка включает блокировку, и сразу после сброса движок может отдать отозванную версию каталога, а actual_data => true у экземпляра блокировку выключает. Если в настройках явно стоит 'use_lock' => true, блокировка остаётся и с actual_data => true, а в файловом кеше без use_lock блокировки и так нет.
Что сломается
Счётчики «Сроков» отстают до двух минут
Кеш счётчиков сбрасывается только у того, кто сам что-то поменял через мобильные контроллеры. Если задачу передвинули в вебе или её изменил коллега, цифры на доске в приложении могут отставать на весь TTL, по умолчанию 120 секунд. Это сказано и в коде: «TTL is the only staleness bound for mutations made outside the mobile app». Если задержка мешает, уменьшите TTL или выключите кеш:
<?php
declare(strict_types=1);
use Bitrix\Main\Config\Option;
Option::set('tasksmobile', 'deadline_counters_cache_ttl', '30');
// или совсем без кеша
Option::set('tasksmobile', 'deadline_counters_cache_enabled', 'N');
Чек-листы в экшенах стали плоскими
tasksmobile.Dod.getDodTree, tasksmobile.Task.Copy.getSourceTaskData (поле CHECKLIST) и tasksmobile.Flow.getTaskCreateMetadata отдают чек-лист плоским списком формата V2 вместо дерева. У getDodTree поля пункта такие: id, nodeId, parentId, parentNodeId, title, isComplete, isImportant, sortIndex, accomplices, auditors, attachments, actions, copiedId. Пустой DoD getDodTree теперь отдаёт пустым массивом, а null возвращает вместе с ошибкой (не найден тип DoD или нет доступа к задачам группы). У Dto\ChecklistAttachmentDto::$fileId тип сменился с int на string.
Из приложения удалены JS-расширения tasks/checklist/flat-tree, tasks/checklist/flat-tree/item и типы tasks/checklist/types/common.d.ts. Свои мобильные расширения, которые их подключали, сломаются. Сторонний код зовёт эти экшены и расширения редко. Тому, кто зовёт, дерево придётся собирать самому по связке parentNodeId → nodeId. В ответах для копирования (getSourceTaskData, getTaskCreateMetadata) id и parentId равны null, а исходный id пункта лежит в copiedId.
Мелочи и находки
TaskProvider::getUsersData()добавляет в ответ данные владельца изsearchParams->ownerId, только еслиCSocNetUser::CanProfileView()разрешает смотреть его профиль. Раньше добавлял всегда.TaskTemplateDataBuilder::prepareChecklist()проверяетACTION_TEMPLATE_READ, раньше проверки не было. При этомFlow::getTaskCreateMetadataActionпо-прежнему отдаёт название, описание, соисполнителей и теги шаблона потока без этой проверки, пустым станет только чек-лист.- Проектная доска берёт счётчики из кеша, только если
Group::canReadGroupTasks()разрешает читать задачи группы, иначе снимок обошёл бы проверку прав. - Черновой чек-лист новой задачи очищается, когда форму закрывают без сохранения. Очистку привязали к подтверждению закрытия, потому что события скрытия виджета генерирует и нативный выбор картинки.
Устаревшие и удалённые API в этой версии
| Символ | Статус | Чем заменять |
|---|---|---|
tasksmobile.Checklist.getShowCompleted
|
Удалено | — |