Представим ситуацию – вам надо сделать небольшой отчет на основе данных из другой системы. Звучит обыденно и вы сразу в голове представляете, что надо будет делать: узнать какие будут входные данные и в каком виде они к нам поступят, какая будет логика отчета (что на что надо умножить и т.д.) и в каком виде отчет должен быть представлен (график, диаграмма, таблица и т.д.), реализовать.

Но что, если я вам скажу, что это должна быть не какая-то новая система, а плагин для Jira. Все вышесказанное никуда не уходит, но добавляются нюансы. Вот о таких нюансах (и как не вылететь из-за них из всех разумных сроков) эта статья.

Начало положено

У нас в группе компаний НЛМК для отслеживания задач используется Jira. И естественно в процессе использования она была сильно адаптирована под наши рабочие процессы (много кастомных полей, несколько workflow под разные типы задач и т.д.). И вот назрела необходимость сделать небольшой отчет, который будет агрегировать информацию по задачам на разработку (в терминологии НЛМК – задание на изменение или просто ЗНИ) в разрезе этих кастомных полей. Как уже было написано выше, задача довольно таки тривиальная и многие сейчас скажут – “Да я подобные задачи делаю по 2 каждый день. Не вижу проблемы”. Мы тоже сначала не видели.

К отчету были приведены следующие требования:

  • возможность задать параметры отчета, которые будут выступать фильтрами для ЗНИ, которые должны попасть в отчет;

  • сам отчет будет представлен в виде таблицы;

  • должна быть возможность выгрузить отчет в виде excel-файла.

Если говорят, что надо делать, значит сделаем. После небольшого мозгового штурма были 2 основных варианта:

  • реализовать функционал в качестве плагина для JIRA;

  • сделать свою систему, которая будет использовать Jira в качестве master-системы.

Со вторым подходом все понятно: все свое кастомное (front, back, экспорт в excel), стучимся в Jira по REST и запрашиваем необходимую информацию. Займет, предположительно, больше времени, но на выходе получим расширяемую систему с претензиями на рост.

Начали копать про плагины для Jira. Сначала все выглядело не очень позитивно. Но потом выяснилось, что Atlassian SDK позволяет добавить в плагин модуль report. Читаем первые 2 абзаца документации (приведу тезисно):

  • модуль позволяет реализовать отчет на основе данных из Jira (неудивительно);

  • позволяет сделать как html-представление, так и в виде excel-файла;

  • позволяет задать пользователю параметры перед формирование отчета.

Выглядит словно под нас делали, но мы не стали спешить радоваться и решили сначала посмотреть, как это все предлагают реализовывать.

Начальные параметры указываются непосредственно
в atlassian-plugin.xml:

<properties>
  <property>
    <key>startDate</key>
    <name>report.startdate</name>
    <description>report.startdate.description</description>
    <type>date</type>
  </property>
  <property>
    <key>endDate</key>
    <name>report.issuecreation.enddate</name>
    <description>report.enddate.description</description>
    <type>date</type></property>
  </property>
  <property>
    <key>projectid</key>
    <name>report.issuecreation.projectid.name</name>
    <description>report.projectid.description</description>
    <type>multiselect</type>
    <values class="com.company.report.valuesgenerator.ProjectsGenerator"/>
  </property>
</properties>

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

А что по экспорту в excel? В основном классе отчета можно переопределить метод isExcelViewSupported класса AbstractReport, чтобы он возвращал true и тогда в углу отчета появляется магическая кнопка для экспорта в excel-файл.

Что из этого всего вытекает:

  • не надо самим делать полностью front, лишь непосредственно страницу отчета;

  • не надо самим делать экспорт в excel;

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

На основе всего вышесказанного было принято решение реализовывать отчет в виде плагина для Jira.

Первый блин - не комом, но могло быть и лучше

На основе всего изученного выше начали работу. Делали все так сказать по фэн-шую с небольшими вкраплениями собственных идей. Но как оказалось не все так гладко в датском королевстве.

Начнем с экрана с начальными параметрами. Jira правда сгенерировала этот экран на основе указанного нами xml, но вот красота сего произведения оставляла желать лучшего. И если с полями для выбора дат все было вполне приемлемо, то вот с multiselect все оказалось хуже.

Из коробки получилось следующее
Из коробки получилось следующее

На выходе получался стандартный select с атрибутом multiple. С одной стороны, все работает – значения успешно прокидываются в select, пользователь может выбрать несколько значений, который потом успешно попадают в основной класс отчета. С другой стороны, пользоваться этим было откровенно неудобно, особенно если у параметра было много допустимых значений (больше 5).

Далее возникла проблема экспортом отчета в excel. Опять же, при нажатии кнопки экспорта, пользователю предлагалось загрузить на компьютер файл с форматом .xls, который можно было открыть и увидеть ту же информацию. Однако как оказалось это не настоящий excel, а просто html-файл с форматом .xls. Excel достаточно умный чтобы открыть такой файл, но вот дальнейшая работа с ним проблематична – если надо дополнительно что-то посчитать или не дай бог построить сводный отчет, то беда.

С этой проблемой нам удалось справиться. Jira позволяет в плагине добавить свой REST-endpoint, который будет казаться частью самой Jira, что мы и сделали. Отвечал этот endpoint за генерацию «настоящего» excel-файла по параметрам с первого экрана. Чтобы его вызвать была добавлена соответствующая кнопка на экран с самим отчетом.

Следующая проблема, с которой нам пришлось бороться это проблема прав. В Jira все отчеты, реализованные через модуль report попадают во вкладку "Отчеты" экрана проекта. Получается, что все пользователи могут этот отчет вызвать, что нас категорически не устраивало. После некоторых раздумий пришли к такому решению: проверять права на этапе генерирования отчета и в случае если у пользователя нет прав на данный отчет, после экрана с параметрами выдавать другую страницу с соответствующим сообщением.

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

Надо еще подумать

Начали думать, как нам быть и что делать. Посмотрим, что происходит под капотом.

Подкапотное пространство до тюнинга
Подкапотное пространство до тюнинга

Jira из xml генерирует начальную страницу для выбора параметров отчета. Для каждого select в плагине должен присутствовать класс реализующий интерфейс ValuesGenerator. В качестве примера можно привести генератор для проектов:

public class ProjectsGenerator implements ValuesGenerator {

    @Override
    public Map getValues(Map map) {
        final ProjectManager projectManager = ComponentAccessor.getProjectManager();
        return projectManager.getProjects().stream()
                        .collect(Collectors.toMap(Project::getKey, Project::getName));
    }
}

После того как будут получены значения для всех select интерфейс выбора параметров будет предоставлен пользователю. Вот на этом моменте уже появляются 2 проблемы:

  • не можем вклиниться в процесс генерации этого экрана и сделать его более приятным глазу;

  • на данном этапе нет возможности провалидировать параметры, выбранные пользователем из-за чего валидация в основном классе отчета.

Проблема с правами возникает из-за того, что создатели Jira предполагают, что все отчеты, реализованные через модуль report должны быть доступны через соответствующую вкладку в проекте. В рамках нашей задачи такой подход нас не устраивает.

После тщательного изучения документации нашли что есть такой модуль как webwork. Суть его в том, что в рамках него можно объявлять несколько связок url-шаблон-класс с переходами от одной связки к другой. Кроме того, в этом же модуле можно сразу указать какие роли требуются для перехода по данному url. В atlassian-plugin.xml это выглядит следующим образом (пример взят из документации):

<webwork1 key="reference-actions" name="Reference WebWork Action" class="java.lang.Object" roles-required="use">
  <actions>
    <action name="com.atlassian.jira.dev.reference.plugin.actions.PreparedReferenceAction" alias="PreparedReferenceAction" roles-required="sysadmin">
      <view name="success">templates/actions/prepared-reference-action.vm</view>
    </action>
    <action name="com.atlassian.jira.dev.reference.plugin.actions.ReferenceAction" alias="ReferenceAction">
      <view name="success">templates/actions/reference-action.vm</view> </action>
  </actions>
</webwork1>

Работа плагина с учетом нового подхода будет выглядеть следующим образом:

Подкапотное пространство после тюнинга
Подкапотное пространство после тюнинга

Можно сделать так сказать двойную проверку прав, которая будет происходить средствами самой Jira:

  • на уровне видимости кнопки – реализуется с помощью condition для web-item;

  • на уровне action в модуле webwork (на случай если у пользователя осталась ссылка на отчет, а права у него забрали).

Теперь касательно интерфейса. Если мы не можем вклиниться в его генерацию мы просто реализуем свой. В таком случае будет возможность и навести красоту, и вынести валидацию параметров из основного класса отчета в класс для страницы с параметрами.

Соответственно в нашем случае описание модуля будет выглядеть следующим образом:

<webwork1 key="report" name="report-webwork" i18n-name-key="report.name" class="java.lang.Object" roles-required="report-role" >
  <description key="report.description">Report-webwork Plugin</description>
  <actions>
    <action name="com.report.webwork.ReportConfigurationAction" alias="ReportConfiguration">
      <view name="report-configuration">/templates/configuration/report-configuration.vm</view>
    </action>
    <action name="com.report.webwork.WebReportAction" alias="WebReport">
      <view name="view">/templates/view/html-view.vm</view>
    </action>
  </actions>
</webwork1>

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

Второй блин

Решили идти итерациями:

  1. перевод текущего функционала на webwork;

  2. добавление дополнительных «хотелок» (подсветка строк в отчете, добавление новых столбцов и т.д.);

  3. решение проблемы с правами.

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

От нас оставалось только преобразовать это все в velocity-шаблон и привязать к определенному action в webwork. Конфигурация модуля выглядит следующим образом:

<webwork1 key="report" name="report-webwork" i18n-name-key="report.name" class="java.lang.Object" roles-required="report-role" >
  <description key="report.description">Report-webwork Plugin</description>
  <actions>
    <action name="com.report.webwork.ReportConfigurationAction" alias="ReportConfiguration">
      <view name="report-configuration">/templates/configuration/report-configuration.vm</view>
    </action>
    <action name="com.report.webwork.WebReportAction" alias="WebReport">
      <view name="view">/templates/view/html-view.vm</view>
    </action>
  </actions>
</webwork1>

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

Был добавлен web-item, который представлял собой ссылку на action с конфигурацией отчета. В результате в верхней панели появилась кнопка для вызова отчета.

REST-endpoint для экспорта в excel в итоге переехал без изменений.

На выходе получился отчет с приятным интерфейсом, той же функциональностью (за мелкими улучшениями) и реализованный более гибким способом.

Комментарии (0)