ui · UI-библиотека 26.693.0 Заметное

UI 26.693.0: загрузчик называет причину отказа, а вьювер прячет кнопку скачивания

3 мин чтения
Узнавайте о ломающих изменениях Битрикса раньше, чем они доедут до прода: свежие разборы — в канале @bxmax_updates

В ui 26.693.0 загрузчик файлов перед сохранением ещё раз проверяет временный файл и при отказе отдаёт текст ошибки из CFile::CheckFile, а при превышении дисковой квоты кладёт в ошибку причину disk_quota_exceeded. Вьювер теперь прячет кнопку скачивания у отдельного файла, а FeaturePromoter.show() принимает ширину слайдера. API не ломается, но если у вас свои UploaderController или e2e-тесты на Input из расширения ui.system.input (BX.UI.System.Input.Input), прочитайте раздел про проверки.

Новое

Спрячьте кнопку скачивания во вьювере

У BX.UI.Viewer.Item появилась опция downloadDisabled: true, в разметке ей соответствует атрибут data-viewer-download-disabled="true". Для такого элемента вьювер снимает с кнопки скачивания href и прячет её, пропускает runAction('download') и не берёт ссылку из action download. Флаг читается методом isDownloadDisabled(). Если вьювер на странице ещё не подключён, подключите его: \Bitrix\Main\UI\Extension::load('ui.viewer');.

        <img
	src="/upload/contracts/42-preview.jpg"
	data-viewer
	data-viewer-type="image"
	data-src="/upload/contracts/42.jpg"
	data-title="Договор 42"
	data-viewer-download-disabled="true"
>

    

Если элементы собираете в JS:

        const item = new BX.UI.Viewer.Image({
	src: '/upload/contracts/42.jpg',
	title: 'Договор 42',
	downloadDisabled: true,
});

BX.UI.Viewer.Instance.setItems([item]).then(() => BX.UI.Viewer.Instance.open(0));

    

Флаг меняет только интерфейс и файл не защищает. Без downloadUrl метод getDownloadUrl() по-прежнему отдаёт src, то есть ту же ссылку, по которой вьювер открыл файл. Доступ закрывайте на сервере. Для элементов из DOM работает только атрибут, потому что setPropertiesByNode() перезаписывает флаг значением из ноды и опция конструктора там не действует.

Узнайте, что загрузку отклонила квота

Перед TempFile::commit() загрузчик теперь сам прогоняет CFile::CheckFile по имени, размеру и MIME временного файла. Проверка стоит на всех трёх путях финализации: последний чанк обычной загрузки, completePresigned() и finalizeParallel(). Отказ приходит ошибкой UploaderError::CHECK_FILE_FAILED, а при нехватке места у неё в customData['reason'] лежит UploaderError::FILE_VALIDATION_REASON_DISK_QUOTA, то есть строка disk_quota_exceeded.

Пользователь это заметит, если место кончилось уже во время загрузки. Квоту CheckFile проверял и раньше, но только на старте, по заявленному размеру. Если к финишу места не оставалось, SaveFile молча возвращал false, и человек видел общее «Не удалось сохранить файл на сервере.». Теперь в этом случае он видит текст причины из CFile::CheckFile. Квота проверяется, только если в настройках главного модуля задано ограничение дискового пространства (disk_space).

Код причины пригодится, чтобы узнать о закончившемся месте раньше, чем придут жалобы:

        <?php declare(strict_types=1);

namespace Vendor\Docs\Integration\UI;

use Bitrix\Main\Diag\Logger;
use Bitrix\UI\FileUploader\UploaderController;
use Bitrix\UI\FileUploader\UploaderError;
use Bitrix\UI\FileUploader\UploadResult;

final class ContractUploaderController extends UploaderController
{
	// isAvailable(), getConfiguration(), canUpload() и остальные методы как были

	public function onUploadError(UploadResult $uploadResult): void
	{
		foreach ($uploadResult->getErrors() as $error) {
			$reason = $error->getCustomData()['reason'] ?? null;

			if (
				$error->getCode() === UploaderError::CHECK_FILE_FAILED
				&& $reason === UploaderError::FILE_VALIDATION_REASON_DISK_QUOTA
			) {
				// логгер vendor.docs.quota описан в секции loggers файла .settings.php
				Logger::create('vendor.docs.quota')?->warning('Upload refused: disk quota exceeded');
			}
		}
	}
}

    

Квоту ядро распознаёт по строке. Ошибку CFile::CheckFile оно сравнивает с GetMessage('FILE_BAD_QUOTA'), а в комментарии рядом объясняют, что CheckFile сообщает причину только локализованной строкой. JS-часть disk_quota_exceeded пока не читает, значение встречается только в Uploader.php и UploaderError.php. Похоже на заготовку под отдельный интерфейс для превышения квоты.

Задайте ширину слайдера с промо

FeaturePromoter.show() принимает { width }. Слайдер берёт её, если это положительное число, иначе остаётся ширина провайдера, по умолчанию 700. Ширину заодно начал учитывать и BX.UI.InfoHelper.show(code, { width }). Если промо открывается попапом (PopupProvider), опция ни на что не влияет.

        // в PHP: \Bitrix\Main\UI\Extension::load('ui.info-helper');
const button = document.querySelector('[data-promo-code]');
const promoter = new BX.UI.FeaturePromoter({ code: button.dataset.promoCode });
promoter.show({ width: 960 });

// или через старый вход
BX.UI.InfoHelper.show(button.dataset.promoCode, { width: 960 });

    

Проверьте e2e-селекторы и свой UploaderController

Затронет немногих, но поведение поменялось в трёх местах.

  • Input из расширения ui.system.input (BX.UI.System.Input.Input) с опцией dataTestId выводит у <input> атрибут data-testid вместо data-test-id. Упадут только автотесты с селекторами [data-test-id=...]. Многострочный вариант с <textarea> этот атрибут не выводил и не выводит.
  • Если commit() или новая проверка CheckFile отказывают в completePresigned() или finalizeParallel(), ошибка теперь идёт через handleUploadError() и вызывает onUploadError() вашего контроллера. Раньше на этих путях её возвращали без хука, так что уведомлений из хука станет больше. На обычной чанковой загрузке хук вызывался и раньше, но отказ по квоте или имени файла на финише теперь приходит кодом CHECK_FILE_FAILED вместо SAVE_FILE_FAILED. Если хук ловит SAVE_FILE_FAILED, добавьте второй код.
  • Uploader::remove() сообщает о неудаче: если временный файл не удалился, в RemoveResult придёт UploaderError::FILE_REMOVE_FAILED. Раньше результат удаления игнорировался.

Мелочи и находки

  • В наборе Solid три новые иконки: BX.UI.IconSet.Solid.BITRIX_GPT, SPEAKER и VIBECODE, с классами .ui-icon-set.--s-bitrix-gpt, --s-speaker, --s-vibecode. Первая и последняя нарисованы под BitrixGPT и Vibecode.
  • Во вьювере появились атрибуты для автотестов: data-testid="ui-viewer" на корне, ui-viewer-close-btn и ui-viewer-download-btn на кнопках.
  • Бандл ui.info-helper в dist не совпадает с src. Раньше он был минифицирован, теперь это обычная сборка, и в ней есть Actions.showDemoActivationError() с MessageBox и обработка отказа ui.infoHelper.activateDemoLicense. При этом контроллер поле error не возвращает, lang-ключа в эталоне нет, а в rel нет ui.buttons и ui.dialogs.messagebox. Видимо, бандл собрали из более новой ветки, и это фронт под ошибки активации демо, которую в ui 26.687.0 научили запускать триал VibePlus.

Новая версия вышла — разбор уже в Telegram

В канале @bxmax_updates публикуем каждый свежий разбор: что сломается, что устарело и что появилось в API. Узнаете до того, как обновите прод.

Подписаться

Читайте дальше

ui 26.600.0 Ломающее Свежее

UI 26.600.0: параллельная и presigned-загрузка файлов, поле rich_text и Bootstrap JS 4.6

Дифф UI 26.600.0 даже без языковых файлов и `.min.js` весит 19 МБ, и почти весь этот объём занимают пересобранные бандлы и вендорные библиотеки (один mermaid дал 136 тысяч строк). Из содержательного загрузчик файлов научился принимать части параллельно и отдавать их браузеру для загрузки прямо в S3….

7 мин
ui 26.650.0 Рутинное Свежее

UI 26.650.0: клавиатура в пикере реакций и аудио во вьюере

Релиз на 2 МБ, из PHP в нём только `config.php` расширений и номер версии. Пикером реакций теперь можно управлять с клавиатуры (роль `menu`, стрелки, Escape), у него появились опции `priorityReaction` и `contextAction` и методы `focus()` и `destroy()`. Если пикер привязан к кнопке, ссылке или элемен…

1 мин
ui 26.675.0 Ломающее Свежее

UI 26.675.0: ui.actionpanel переехал в бандл, а rich_text по-новому обходится с квадратными скобками

Модуль ui 26.675.0 собран 26 августа 2026. Из PHP поменялись `Converter` и `Whitelist` в `Bitrix\UI\Format\BBCode`, и пользовательские поля типа `rich_text` теперь иначе сохраняют и индексируют текст с квадратными скобками. На фронтенде старую панель групповых действий `ui.actionpanel` перевели на б…

4 мин
ui 26.687.0 Рутинное Свежее

UI 26.687.0: триал VibePlus в облаке и дизайн чипа TintedBitrixGpt

`Bitrix\UI\Controller\InfoHelper` при активации демо сначала спрашивает у модуля bitrix24, включён ли старт VibePlus, и если да, запускает триал VibePlus вместо обычного демо тарифа. Ветка срабатывает только при подключённом модуле bitrix24 и определённой константе `BX24_HOST_NAME`. В `ui.system.chi…

1 мин
Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.
AI Домовой

AI Домовой История

на связи

пишет…

Можно закрыть чат и перейти на другую страницу. Когда ответ будет готов, на кнопке Домового появится отметка.

Нет истории чатов
AI Домовой

Нужна авторизация

Войдите, чтобы задавать вопросы AI Домовому.

Войти