Фасет drafts

Фасет drafts сохраняет несохраненные изменения экрана в виде черновика и предлагает восстановить черновик, когда пользователь снова открывает экран. Общее описание см. в разделе Как это работает.

Добавление фасета

Объявите пространство имен дополнения в дескрипторе экрана:

<view xmlns="http://jmix.io/schema/flowui/view"
      xmlns:uirec="http://jmix.io/schema/uirecovery/ui"
      title="msg://OrderDetailView.title"
      focusComponent="form">

Затем добавьте элемент uirec:drafts в элемент facets:

<facets>
    <dataLoadCoordinator auto="true"/>
    <uirec:drafts id="draftsFacet"/>
</facets>

В Jmix Studio фасет можно добавить из раздела Facets палитры компонентов.

Фасет работает в любом экране, у которого есть DataContext, и сохраняет изменения, зарегистрированные в нем. В экране деталей черновик относится к редактируемой записи. В других экранах, например в экране списка с редактируемой таблицей данных, у экрана один черновик.

Вы можете просматривать и редактировать атрибуты фасета в Jmix Studio используя панель испектора Jmix UI.

Атрибуты

Поведение фасета в конкретном экране можно изменить с помощью следующих атрибутов:

<facets>
    <dataLoadCoordinator auto="true"/>
    <uirec:drafts id="draftsFacet" restoreMode="AUTO" minSaveInterval="10s"/>
</facets>
minSaveInterval

Минимальное время между двумя сохранениями черновика экрана, например 5s или 1m. Изменения, сделанные в течение этого времени, сохраняются по окончании интервала. Значение по умолчанию задается свойством jmix.uirecovery.drafts.default-min-save-interval.

restoreMode

Способ восстановления черновика при открытии экрана: ASK или AUTO. См. Режимы восстановления. Значение по умолчанию задается свойством jmix.uirecovery.drafts.default-restore-mode.

Сохранение и удаление черновиков

Фасет сохраняет черновик после того, как пользователь изменил данные в экране, но не чаще, чем позволяет minSaveInterval. Когда экран отсоединяется, например потому что пользователь закрыл вкладку браузера, фасет сразу сохраняет оставшиеся изменения.

Фасет удаляет черновик, когда:

  • Пользователь сохраняет изменения.

  • Пользователь закрывает экран и подтверждает, что изменения нужно отменить.

Если сохранить черновик не удалось, ошибка записывается в лог, и экран продолжает работать.

Сохранение вводимых значений

По умолчанию текстовое поле отправляет значение на сервер, когда поле теряет фокус или пользователь нажимает Enter. До этого момента введенное значение отсутствует в модели данных и не может быть сохранено в черновике. Если пользователь вводит длинный текст в одно поле, при сбое весь этот текст может быть потерян.

Чтобы отправлять значение во время ввода, установите для атрибута поля valueChangeMode значение LAZY или TIMEOUT:

<textArea id="commentField" property="comment" height="9.5em"
          valueChangeMode="LAZY" valueChangeTimeout="1000"/>

В этом примере текстовая область отправляет значение, когда пользователь прекращает ввод на одну секунду. Затем значение сохраняется в следующем черновике. Каждое отправленное значение — это запрос к серверу, поэтому используйте эту настройку для полей, в которые пользователи вводят много текста.

Режимы восстановления

Когда экран открывается и для него найден черновик, фасет восстанавливает черновик в соответствии с режимом восстановления.

ASK

Это режим по умолчанию. Фасет показывает диалог с датой черновика:

restore dialog
  • Restore переносит изменения из черновика в экран. Изменения не сохраняются в базу данных, пока пользователь не сохранит экран.

  • Discard удаляет черновик.

  • Not now закрывает диалог и сохраняет черновик. Диалог будет показан снова, когда пользователь в следующий раз откроет экран.

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

restore dialog version differs

Предупреждение показывается для сущностей с оптимистичной блокировкой, то есть сущностей с атрибутом версии.

AUTO

Фасет восстанавливает черновик без вопроса и показывает уведомление. Черновик хранится в базе данных, пока пользователь не сохранит экран или не отменит изменения. Если работа снова прервется до этого, черновик останется доступен.

Что восстанавливается

Фасет восстанавливает только те атрибуты, которые изменил пользователь. Остальные атрибуты сохраняют текущие значения.

Фасет пропускает части черновика, которые больше нельзя применить, и восстанавливает остальное. Например, он пропускает:

  • Атрибут, который был удален из сущности в новой версии приложения.

  • Запись, которая была удалена после сохранения черновика.

Если черновик вообще не удается прочитать, фасет удаляет его, и экран открывается без восстановления. Пользователь не получает уведомления. Подробности записываются в лог.

Собственная логика восстановления

Чтобы в коде решать, восстанавливать ли черновик и как, задайте делегат восстановления. Фасет вызывает его перед стандартным восстановлением. Делегат получает объект DraftRestoreContext с найденным черновиком и экраном. Если делегат вызывает preventRestore(), фасет не восстанавливает черновик и не показывает диалог.

В следующем примере экран не предлагает черновики старше одного дня и удаляет их:

@ViewComponent
private DraftsFacet draftsFacet;

@Autowired
private TimeSource timeSource;

@Install(to = "draftsFacet", subject = "restoreDelegate")
private void draftsFacetRestoreDelegate(final DraftRestoreContext context) {
    OffsetDateTime draftDate = context.getDraft().getCreatedDate();
    OffsetDateTime minDate = timeSource.now().toOffsetDateTime().minus(Duration.ofDays(1));
    if (draftDate.isBefore(minDate)) {
        context.preventRestore(); (1)
        draftsFacet.deleteDrafts(); (2)
    }
}
1 Фасет не восстанавливает черновик и не показывает диалог.
2 Удаляет черновик текущего экрана и записи.

DraftRestoredEvent

Фасет отправляет DraftRestoredEvent после восстановления черновика. Событие отправляется в обоих режимах восстановления. В этот момент восстановленные значения уже находятся в экране, поэтому можно обновить UI или проверить данные. Изменения, сделанные в обработчике события, сохраняются в следующем черновике.

Метод события getDraft() возвращает восстановленный черновик, а getRestoredEntities() — экземпляры сущностей, которые были изменены при восстановлении.

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

В следующем примере экран проверяет восстановленные значения и показывает ошибки валидации:

@ViewComponent
private JmixFormLayout form;

@Autowired
private ViewValidation viewValidation;

@Subscribe("draftsFacet")
public void onDraftRestored(final DraftsFacet.DraftRestoredEvent event) {
    ValidationErrors errors = viewValidation.validateUiComponents(form);
    if (!errors.isEmpty()) {
        viewValidation.showValidationErrors(errors);
    }
}

Методы

Интерфейс DraftsFacet имеет следующие методы:

  • saveDraftNow() сохраняет черновик немедленно, не дожидаясь окончания minSaveInterval.

  • deleteDrafts() удаляет черновик текущего экрана и записи.

  • setMinSaveInterval() и setRestoreMode() изменяют значения атрибутов.

  • setRestoreDelegate() задает делегат восстановления.

  • addDraftRestoredListener() добавляет слушатель DraftRestoredEvent.