1. Привязка календаря к данным

В этом разделе вы создадите:

  • Сущность JPA Meeting.

  • Компонент FullCalendar с поставщиком данных.

Событие встречи

Сущность Meeting будет представлять событие в компоненте FullCalendar. Для корректного отображения требуются определенные свойства:

  • name - название события.

  • startDate - дата и время начала события. Компонент не будет отображать события без startDate.

  • endDate - дата окончания события. Если endDate не указано, компонент применит продолжительность по умолчанию на основе свойства allDay. В этом руководстве свойство allDay не используется; следовательно, события рассматриваются как события, не охватывающие весь день.

Создание сущности Meeting

Подробные инструкции по созданию сущностей JPA смотрите в разделе Простой CRUD самоучителя.

Сущность Meeting имеет следующие атрибуты:

  • name типа String type. Установите флажок Mandatory.

  • startDate типа LocalDateTime. Установите флажок Mandatory.

  • endDate типа LocalDateTime.

  • user - тип атрибута Association, сущность User в качестве типа Java и кардинальность many-to-one (многие-к-одному). Установите флажок Mandatory.

Сущность Meeting не требует стандартных экранов списка и деталей, поскольку она будет генерироваться программно и отображаться в компоненте FullCalendar.

Генерация Meeting

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

Наилучший момент для проверки того, завершил ли пользователь все этапы, - это событие PreSaveEvent контекста данных (DataContext). Слушатель этого события проверяет наличие незавершенных этапов адаптации. Если незавершенных этапов нет, создается новое событие встречи.

@Subscribe(target = Target.DATA_CONTEXT)
public void onPreSave(final DataContext.PreSaveEvent event) {
    List<UserStep> userSteps = userStepsDc.getItems().stream()
            .filter(us -> us.getCompletedDate() == null)
            .toList();
    if (userSteps.isEmpty()) {
        generateOnboardingResultsMeeting();
    }
}

Далее мы реализуем метод generateOnboardingResultsMeeting(). Этот метод создает экземпляр события Meeting, запланированного на следующий рабочий день.

protected void generateOnboardingResultsMeeting() {
    Meeting meeting = dataContext.create(Meeting.class); (1)
    meeting.setName("Results meeting");
    meeting.setUser((User) currentAuthentication.getUser());

    int inDays = LocalDate.now().getDayOfWeek() == DayOfWeek.FRIDAY ? 3 : 1; (2)
    LocalDateTime start = LocalDateTime.of( (3)
            LocalDate.now().plusDays(inDays),
            LocalTime.of(9, 30));

    meeting.setStartDate(start);
    meeting.setEndDate(start.plusMinutes(30));
}
1 Создает и добавляет новый экземпляр Meeting в DataContext, автоматически сохраняя сущность.
2 Вычисляет следующий рабочий день; если сегодня пятница, встреча планируется на понедельник.
3 Устанавливает дату и время начала встречи на 9:30 утра следующего рабочего дня.

Добавление компонентов в MyCalendar

Сначала создайте новый пустой экран с именем MyCalendar.

creating my calendar view

Studio сгенерирует и отобразит пустой экран в дизайнере.

Загрузка данных

Перед добавлением компонента FullCalendar создайте контейнер коллекций для сущности Meeting.

В панели действий нажмите кнопку Add Component, перейдите в раздел Data components и дважды щелкните Collection container. В появившемся диалоговом окне выберите Meeting в поле Entity и нажмите OK.

<collection id="meetingsDc" class="com.company.onboarding.entity.Meeting">
    <loader id="meetingsDl" readOnly="true">
        <query>
            <![CDATA[select e from Meeting e]]>
        </query>
    </loader>
    <fetchPlan extends="_base"/>
</collection>

Текущая конфигурация загрузчика данных извлекает все события от всех пользователей. Однако пользователи должны видеть только свои собственные события. Для реализации этой фильтрации необходимо изменить запрос JPQL - либо с помощью редактора, либо вручную - добавив условие, которое ограничивает результаты текущим пользователем, который вошел в систему:

<query>
    <![CDATA[select e from Meeting e where e.user = :user]]>
</query>

Мы получаем данные о текущем авторизованном пользователе из бина CurrentAuthentication и передаем эту информацию загрузчику данных в обработчике события BeforeShowEvent:

  • Подпишитесь на событие BeforeShowEvent.

  • Инжектируйте загрузчик meetingsDl.

  • Инжектируйте бин CurrentAuthentication.

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

@ViewComponent
private CollectionLoader<Meeting> meetingsDl;
@Autowired
private CurrentAuthentication currentAuthentication;

@Subscribe
public void onBeforeShow(final BeforeShowEvent event) {
    final User user = (User) currentAuthentication.getUser();
    meetingsDl.setParameter("user", user);
    meetingsDl.load();
}

Добавление компонента FullCalendar

В панели действий нажмите Add Component, найдите элемент FullCalendar и дважды щелкните по нему.

После этого будет создан новый элемент calendar. Настройте атрибуты id, height и width, как показано ниже.

<calendar:calendar id="calendar"
                   height="100%"
                   width="100%"/>

Добавление поставщика данных

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

Чтобы добавить ContainerDataProvider в компонент FullCalendar:

  1. Выберите компонент calendar в панели структуры Jmix UI или в XML-дескрипторе экрана.

  2. Нажмите кнопку Add на панели инспектора.

  3. В выпадающем меню выберите Data ProvidersContainerDataProvider.

add container data provider

В появившемся диалоговом окне выберите meetingsDc.

Элемент containerDataProvider позволяет настроить сопоставление свойств сущности. Сущность Meeting содержит следующие свойства:

  • name

  • startDate

  • endDate

Поэтому следует указать следующие атрибуты:

<calendar:dataProviders>
    <calendar:containerDataProvider dataContainer="meetingsDc"
                                    title="name"
                                    startDateTime="startDate"
                                    endDateTime="endDate"/>
</calendar:dataProviders>

Давайте посмотрим: полное описание нашего календаря выглядит следующим образом:

<calendar:calendar id="calendar"
                   height="100%"
                   width="100%">
    <calendar:dataProviders>
        <calendar:containerDataProvider dataContainer="meetingsDc"
                                        title="name"
                                        startDateTime="startDate"
                                        endDateTime="endDate"/>
    </calendar:dataProviders>
</calendar:calendar>

Запустите приложение и войдите в систему как пользователь admin. У пользователя admin нет шагов онбординга, поэтому необходимо их сгенерировать:

  • Перейдите в экран User.list, выбрав Users в меню приложения.

  • Выберите пользователя admin в DataGrid и нажмите кнопку Edit. Затем заполните поле Joining Date, сгенерируйте шаги онбординга и сохраните изменения.

  • Перейдите в экран MyCalendar, выбрав My Calendar в меню приложения.

getting started data binding result