Данная статья описывает важные обновления, представленных в только что вышедшем релизе Jmix 2.3.
Полная информация об изменениях и рекомендации по апгрейду проектов доступны на странице документации Что нового.
Дополнение Superset
Apache Superset - это ведущий открытый программный продукт для исследования и визуализации данных. Он позволяет создавать легко настраиваемые дэшборды, содержащие различные графики. Графики заполняются из датасетов, которые получают данные из вашей БД с помощью SQL-запросов.
Дополнение Jmix Superset позволяет легко подключить ваше приложение к серверу Apache Superset и встроить дэшборды в экраны Jmix. Например, основной экран приложения Bookstore может содержать дэшборд с агрегированной информацией о заказах клиентов:
Достаточно указать URL-адрес и учетные данные пользователя для подключения к серверу Superset, и дополнение позаботится о запросе, обновлении и использовании токенов безопасности при отображении встроенных дэшбордов.
После создания дэшборда в Superset, его нужно подготовить к встраиванию. Superset генерирует идентификатор для ссылки на этот дэшборд извне.
UI-компонент dashboard
, предоставляемый дополнением, позволяет включить дэшборд в экран приложения. Вам нужно только указать идентификатор дэшборда в атрибуте embeddedId
:
<superset:dashboard id="ordersDashboard"
embeddedId="4bc14bf5-a3ec-4151-979e-a920420e1f66"
height="100%" width="100%" maxWidth="50em"/>
Сервер Superset напрямую подключается к базе данных приложения. Чтобы фильтровать данные на дэшбордах в соответствии с разрешениями пользователя или любыми другими критериями, вы можете передавать список ограничений из экрана в дэшборд. В следующем примере дэшборд будет показывать данные только для текущего арендатора в мультиарендном приложении:
@Install(to = "ordersDashboard", subject = "datasetConstraintsProvider")
private List<DatasetConstraint> ordersDashboardDatasetConstraintsProvider() {
DatasetConstraint constraint = new DatasetConstraint(25,
"tenant = '" + tenantProvider.getCurrentUserTenantId() + "'");
return List.of(constraint);
}
Для получения подробной информации об использовании дополнения Superset с вашим Jmix-приложением см. документацию по дополнению Superset.
Поддержка OpenSearch
Теперь вы можете использовать дополнение Jmix Search с сервисом OpenSearch. Все функции дополнения (декларативные определения индексов, очередь индексации, поле поиска в UI и т.д.) работают одинаково как с движком OpenSearch, так и с Elasticsearch. Выбор между OpenSearch и Elasticsearch сводится к указанию соответствующего стартера в зависимостях build.gradle
. Когда дополнение устанавливается из Marketplace, по умолчанию выбирается OpenSearch.
Фрагменты
Фрагмент - это новый строительный блок пользовательского интерфейса, предназначенный для повторного использования кода и декомпозиции сложных структур UI. С точки зрения функциональности, фрагменты находятся между экранами и составными компонентами.
Так же, как и экран, фрагмент может иметь XML-дескриптор с компонентами данных и действиями. Он поддерживает внедрение компонентов и обработчики событий в классе фрагмента. Студия предоставляет шаблон для создания пустого фрагмента и тот же UI-дизайнер, что и для экранов.
С другой стороны, фрагмент может использоваться в качестве компонента экранов и других фрагментов.
Цель фрагментов - предоставить больше гибкости в структурировании и повторном использовании кода UI, связанного с моделью данных.
Приведенный ниже пример дает представление о том, как создавать и использовать фрагменты. Этот простой фрагмент представляет данные встраиваемой сущности Money
. UI-дизайнер с XML-кодом фрагмента и предварительным просмотром выглядит следующим образом:
Класс фрагмента (также известный как контроллер) может определять сеттеры для приема параметров из хост-экрана (или хост-фрагмента). В нашем случае он получает экземпляр Money
и устанавливает его в свой собственный контейнер данных:
@FragmentDescriptor("money-fragment.xml")
public class MoneyFragment extends Fragment<JmixFormLayout> {
@ViewComponent
private InstanceContainer<Money> moneyDc;
public void setMoney(Money money) {
moneyDc.setItem(money);
}
}
Чтобы включить фрагмент в экран, используется элемент fragment
, в котором указывается класс фрагмента. Наш хост-экран содержит два экземпляра одного и того же фрагмента:
<vbox>
<h4 text="msg://price"/>
<fragment id="unitPriceFragment"
class="io.jmix.bookstore.view.moneyfragment.MoneyFragment"/>
</vbox>
<vbox>
<h4 text="msg://discount"/>
<fragment id="discountFragment"
class="io.jmix.bookstore.view.moneyfragment.MoneyFragment"/>
</vbox>
Контроллер хост-экрана вызывает методы API фрагмента, чтобы передать экземпляры Money
:
@ViewComponent
private MoneyFragment unitPriceFragment;
@ViewComponent
private MoneyFragment discountFragment;
@Subscribe
public void onReady(final ReadyEvent event) {
unitPriceFragment.setMoney(orderLineDc.getItem().getUnitPrice());
discountFragment.setMoney(orderLineDc.getItem().getDiscount());
}
Репозитории данных
Этот релиз завершает реализацию поддержки репозиториев Spring Data в качестве "граждан первого сорта" в экосистеме Jmix. Теперь вы можете легко использовать их в экранах для загрузки и сохранения данных, сохраняя совместимость со всеми стандартными функциями пользовательского интерфейса Jmix, такими как фильтрация, разбивка на страницы и сортировка.
При создании экрана с помощью мастера, обратите внимание на флажок Use Data Repository в разделе Advanced. Если вы включите его, вы сможете выбрать существующий репозиторий данных. Мастер сгенерирует экран с делегатами загрузки и сохранения, вызывающими методы вашего репозитория.
Делегат загрузки списка извлечет Spring Data PageRequest
из объекта Jmix LoadContext
и предоставит условия фильтрации и другие параметры репозиторию данных в объекте JmixDataRepositoryContext
. Вы можете изменить логику делегата, например, чтобы задать начальную сортировку:
@Install(to = "customersDl", target = Target.DATA_LOADER)
private List<Customer> loadDelegate(LoadContext<Customer> context) {
// convert Jmix paging and sorting parameters to Spring Data PageRequest
PageRequest pageable = JmixDataRepositoryUtils.buildPageRequest(context);
if (pageable.getSort().isEmpty()) {
// set initial sorting
pageable = pageable.withSort(Direction.ASC, "firstName", "lastName");
}
// provide Jmix conditions, fetch plan and hints
JmixDataRepositoryContext jmixContext = JmixDataRepositoryUtils.buildRepositoryContext(context);
// invoke repository method and return the page content
return repository.findAll(pageable, jmixContext).getContent();
}
Приведенный выше код делает то же самое, что и следующий JPQL в загрузчике:
<loader id="customersDl" readOnly="true">
<query>
<![CDATA[select e from bookstore_Customer e
order by e.firstName asc, e.lastName asc]]>
</query>
</loader>
Все методы репозиториев, которые расширяют JmixDataRepository
, теперь поддерживают JmixDataRepositoryContext
в качестве дополнительного параметра. Это делает репозитории данных совместимыми с компонентами genericFilter
и propertyFilter
и декларативными загрузчиками данных.
Ленивые вкладки TabSheet
Компонент TabSheet обычно используется, когда на экране много UI-компонентов и нужно сгруппировать их на разных вкладках.
В этом релизе мы добавили возможность помечать вкладку как lazy
. Содержимое такой вкладки не будет загружаться автоматически при открытии экрана. Если использовать эту функцию для вкладок, содержащих много компонентов и требующих загрузки дополнительных данных, то можно значительно улучшить производительность экранов.
Загрузка данных и другая инициализация для ленивых вкладок должна выполняться в слушателе SelectedChangeEvent
компонента tabSheet
, например:
@ViewComponent
private CollectionLoader<Position> positionsDl;
private boolean positionsInitialized;
@Subscribe("tabSheet")
public void onTabSheetSelectedChange(final JmixTabSheet.SelectedChangeEvent event) {
if ("positionTab".equals(event.getSelectedTab().getId().orElse(null))
&& !positionsInitialized) {
positionsDl.load();
positionsInitialized = true;
}
}
Имейте в виду также, что компоненты, расположенные на ленивой вкладке, не могут быть инжектированы в класс экрана, так как они не существуют в этот момент. Поэтому вам нужно использовать метод UiComponentUtils.getComponent()
для их получения после инициализации вкладки.
Компонент TwinColumn
Новый компонент twinColumn
является отличным дополнением к библиотеке UI-компонентов Jmix. Он предоставляет пользователям знакомый и удобный способ выбора элементов из списка:
Дополнение Authorization Server
Мы извлекли модуль Authorization Server в отдельное дополнение со своей документацией и процессом установки. Ранее он устанавливался вместе с дополнением Generic REST. Поэтому теперь, при установке Generic REST, вам необходимо решить, как вы будете защищать его эндпойнты: используя дополнения Authorization Server или OIDC, или другими средствами.
Новая функция дополнения Authorization Server - реализация гранта Resource Owner Password Credentials. Этот тип гранта не рекомендуется спецификацией OAuth, но мы получили много запросов от разработчиков приложений и решили реализовать его. Его можно использовать в доверенных, устаревших или строго контролируемых средах для простой аутентификации клиентов REST как зарегистрированных пользователей приложения Jmix.
Агрегация файлов Liquibase changelog
Самая заметная новая функция в Studio - это возможность агрегировать существующие журналы изменений Liquibase. Она позволяет разработчикам объединять несколько последних журналов изменений в один и избавляться от дублированных действий в наборах изменений.
Рассмотрим следующую ситуацию: в результате итеративной разработки модели данных у вас есть три журнала изменений. Первый добавляет столбец ALPHA
, второй добавляет столбец BETA
, а третий добавляет GAMMA
и удаляет ALPHA
. Таким образом, изменения, введенные в первом журнале, перекрываются третьим.
Действие Aggregate Liquibase Changelogs доступно в контекстном меню хранилища данных. Оно позволяет выбрать любое количество последних журналов изменений для агрегации. Давайте выберем три журнала изменений, описанных выше:
Результирующий журнал изменений будет включать только изменения, которые действительно приводят схему базы данных в соответствие с моделью данных: добавление столбцов BETA
и GAMMA
:
Studio удалит выбранные файлы журналов изменений и добавит новый агрегированный. Чтобы сохранить набор журналов изменений совместимым с базами данных, где старые журналы уже были выполнены, Studio может добавить предусловие к новым наборам изменений. Это предусловие инструктирует Liquibase не выполнять новые наборы изменений, если первый журнал изменений из замененного списка был выполнен:
<preConditions onFail="MARK_RAN">
<not>
<changeSetExecuted id="1" author="bookstore"
changeLogFile="io/jmix/bookstore/liquibase/changelog/2024/06/27-1-add-alpha.xml"/>
</not>
</preConditions>
Агрегацию журналов изменений следует выполнять с осторожностью, потому что она фактически не анализирует и не воспроизводит содержимое существующих журналов изменений. Вместо этого она генерирует новый журнал для разницы между схемой до первого выбранного журнала и текущей моделью. Поэтому если агрегируемые журналы изменений содержат какие-либо обновления данных или изменения схемы, которые не отражены в модели (например, хранимые процедуры), они будут потеряны.
Очевидно, что наиболее естественный и безопасный способ использования этой функциональности - агрегировать журналы изменений перед коммитом последних изменений в общий репозитории исходного кода или мержем новой функциональности в общую ветку.
Другие улучшения в Studio
Данный релиз представляет несколько новых функций Studio, помогающих в разработке.
- Окно инструментов Jmix предоставляет команду для генерации обработчиков исключений пользовательского интерфейса.
- Команда Convert to в контекстном меню структуры Jmix UI позволяет преобразовать один компонент в другой одним щелчком. Команда Wrap into умеет оборачивать несколько выбранных компонентов во вкладку TabSheet.
- Улучшена компоновка JPQL Designer.
- Обновлена функция генерации Dockerfile.
См. список всех улучшений Studio в нашем багтрекере.
Заключение
В следующем функциональном релизе в октябре 2024 года мы планируем реализовать следующие новые возможности в Jmix UI:
- Интегрировать несколько сторонних JavaScript-компонентов: Calendar, PivotTable, Kanban board.
- Предоставить возможность использовать фрагменты для определения внутренней компоновки элементов VirtualList.
- Реализовать дополнительный режим главного экрана, при котором несколько экранов можно открыть во вкладках внутри главного экрана, а не во вкладках браузера.
Последняя функция является наиболее востребованной разработчиками, которые хотят перенести свои решения с Classic UI. Поэтому мы собираемся предоставить решение для работы с несколькими экранами в одной вкладке браузера, пожертвовав такими возможностями браузера как история и глубокие ссылки.
Еще одна запланированная функция, которая может помочь с миграцией с более старых версий платформы, - это декларативные разрешения на элементы UI. Эта функциональность присутствовала в CUBA Platform и позволяла разработчикам и администраторам приложений ограничивать доступ к произвольным частям пользовательского интерфейса (полям, кнопкам, действиям) без необходимости писать какой-либо код.
В Studio мы собираемся сделать использования инспектора Jmix UI более удобным и предоставить больше редакторов для свойств компонентов пользовательского интерфейса (например для formLayout.responsiveSteps
). Кроме того, мы представим первые результаты нашей работы по интеграции с внешними источниками данных.
Как всегда, мы будем уделять значительное время исправлению ошибок, добавлению небольших функций и улучшению производительности.
Наш подробный план для будущих версий доступен как проект GitHub. Патчи для текущей версии 2.3 будут выходить примерно раз в месяц.
Будем рады увидеть ваши отзывы на нашем форуме!
Спасибо всем, кто отправлял нам PR-ы, делился своими идеями, предложениями и сообщениями об ошибках!