Написание автономного гаджета JQL

Уровень опыта: Новичок

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

Обзор

В этом учебном пособии показано, как написать гаджет, который будет загружать данные из JIRA JQL Query (запроса) в окно гаджета и позволить пользователю щелкнуть по элементу, чтобы загрузить содержимое задач в своем браузере. Для простоты этого руководства мы будем извлекать данные из локальной установки JIRA (localhost: 8070) в локальную установку Confluence (localhost: 8080 / confluence) и использовать файл gadget.xml, поступающий с другого веб-сервера, в этом случае они по-существу обслуживаются нашим SVN-сервером. Чтобы адаптировать учебник к вашей среде, просто измените имя сервера («localhost») и порты («8070» и «8080»), если это необходимо.

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

Ваш гаджет станет автономным гаджетом. Это означает, что он будет полностью состоять из HTML, CSS и Javascript, которые содержатся в спецификации XML-гаджета. Здесь вообще не подключен плагин, вы можете поместить этот XML-файл гаджета на любой веб-сервер, исключая необходимость создания плагина для размещения вашего гаджета. Если вас это интересует, вы можете сравнить автономные гаджеты и гаджеты, встроенные в плагины.

Этот гаджет предполагает, что у вас есть понимание того, как работает OAUTH, и следует за «Пример прохождения гаджета» от Google.

Шаг 1. Создайте спецификацию гаджета

  1. Скопируйте следующий код, чтобы создать базовый XML-файл, который станет вашей спецификацией гаджета:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="My Gadget Title"
  description="My Gadget Description" 
  author="My Name" 
  author_email="my-email-address@example.com">
    <Optional feature="gadget-directory">
      <Param name="categories">Other</Param>
    </Optional>
  </ModulePrefs>
  <Content type="html">
    <![CDATA[
    Hello world!
    ]]>
  </Content>
</Module>

  1. Вставьте код в текстовый редактор и сохраните файл как jql-gadget.xml

 

Шаг 2. Обновите заголовок гаджета и другие описательные данные.

  1. Обновите значения следующих атрибутов в элементе <ModulePrefs> спецификации вашего гаджета:

title

Введите «JQL Gadget».

description

Введите 'Этот гаджет извлекает содержимое из JIRA JQL Query и отображает результаты в окне гаджета.

author

Введите свое имя.

author_email

Введите свой собственный адрес электронной почты или удалите этот атрибут.

  1. Обновите значение параметра категорий categories функции gadget-directory на «JIRA». Это определяет, какая категория вашего гаджета отображается в каталоге гаджета JIRA. ПРИМЕЧАНИЕ: Допустимые значения: «JIRA», «Confluence», «FishEye», «Crucible», «Crowd», «Clover», «Bamboo», «Admin», «Charts», «External Content» и «Other».

Полученный XML должен выглядеть примерно так:


<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="JQL Gadget"
  description="This gadget pulls content from an arbitrary JIRA JQL Query and displays the results in the gadget window"
  author="Atlassian"
  author_email="sales@atlassian.com">
    <Optional feature="gadget-directory">
      <Param name="categories">JIRA</Param>
    </Optional>
  </ModulePrefs>
  <Content type="html">
    <![CDATA[
    Hello world!
    ]]>
  </Content>
</Module>

Шаг 3. Сделайте гаджет доступным на сервере

Поскольку вы разрабатываете автономный гаджет, вы можете разместить свою спецификацию гаджета на любом сервере, который сделает его доступным для контейнера гаджета, такого как страница Confluence или панель управления JIRA. Вы можете разместить XML-файл гаджета на любом веб-сервере в вашем распоряжении. Если вы хотите использовать тот же XML-код, который я использовал, вы можете следовать с помощью размещенных файлов с нашего SVN-сервера. ПРИМЕЧАНИЕ. Эти файлы предполагают, что JIRA работает на localhost: 8070 и Confluence работает на localhost: 8080 / confluence.

Каждый файл сохраняется после каждого шага: jql-gadget-step1.xml, jql-gadget-step2.xml и т. д.

Шаг 4. Добавьте гаджет в страницу Confluence для тестирования.

Ваш гаджет уже может что-то сделать: он может сказать «Привет, мир!». Проверьте его, добавив его на страницу Confluence.

  1. Перейдите в Управление Confluence и нажмите «Внешние гаджеты».
  2. Появится экран «Внешние гаджеты», в котором отображается список гаджетов, доступных в Macro Browser.
  3. Введите URL-адрес спецификации гаджета и нажмите «Добавить».
  4. Измените страницу Confluence, в которую вы хотите добавить свой гаджет.
  5. Нажмите кнопку «Вставить / Редактировать макрос».
  6. Введите «JQL» в поле поиска

РИСУНОК

  1. Выделите гаджет и нажмите кнопку «Добавить», чтобы добавить вики-разметку для макроса гаджета на страницу вики.

Шаг 5. Сделайте гаджет полезным

Теперь вы будете писать JavaScript и HTML-код для извлечения данных из JIRA, чтобы мы могли отображать информацию в гаджете на странице Confluence.

Элемент <Content> в спецификации вашего гаджета содержит рабочие части гаджета. Элемент <Content> состоит из:

  • Объявление CDATA, чтобы предотвратить синтаксический анализатор XML, от попытки проанализировать содержимое гаджета. Включите '<! [CDATA [GADGETDEV:' (без кавычек) в начале и ']]>' (без кавычек) в конце вашего элемента <Content>.
  • Необязательный статический HTML. Когда панель инструментов отображает гаджет, он отобразит этот HTML-код.
  • Дополнительный JavaScript. Вы можете объявить функции JavaScript и вызвать их обычным способом. Обратитесь к API-интерфейсу OpenSocial JavaScript для получения подробной информации о функциях API для конкретных гаджетов, которые должен поддерживать любой контейнер-носитель OpenSocial.
  • Дополнительные таблицы стилей CSS.

В этом уроке вам понадобится функция JavaScript, которая делает REST-вызов JIRA для извлечения данных. Из коробки JIRA предоставляет богатый фреймворк Gadget Javascript Framework, который облегчает разработку гаджетов в качестве плагинов. Мы собираемся использовать это преимущество с помощью вспомогательных файлов javascript с удаленного сервера, чтобы проиллюстрировать, насколько легко можно настроить настроенный гаджет, не касаясь какого-либо кода плагина.

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

Нам также необходимо добавить настройки, чтобы включить этот гаджет для OAUTH, добавив этот XML в тег ModulePrefs


    <Require feature="oauthpopup" />
    <OAuth>
        <Service>
            <Access url="http://localhost:8070/plugins/servlet/oauth/access-token" method="POST" />
            <Request url="http://localhost:8070/plugins/servlet/oauth/request-token" method="POST" />
            <Authorization url="http://localhost:8070/plugins/servlet/oauth/authorize?oauth_callback=http%3A%2F%2Foauth.gmodules.com%2Fgadgets%2Foauthcallback" />
        </Service>
    </OAuth>

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


  <Content type="html">
    <![CDATA[
        <!-- shindig oauth popup handling code -->
        <script src="http://svn.atlassian.com/svn/public/contrib/tutorials/jira-standalone-jql-gadget/static/js/popup.js"></script>

        <div id="main" style="display: none">
        </div>

        <div id="approval" style="display: none">
          <img src="http://svn.atlassian.com/svn/public/contrib/tutorials/jira-standalone-jql-gadget/static/images/new.gif">
          <a href="#" id="personalize">Personalize this gadget</a>
        </div>

        <div id="waiting" style="display: none">
          Please click
          <a href="#" id="approvaldone">I've approved access</a>
          once you've approved access to your data.
        </div>

        <script type="text/javascript">
          // Display UI depending on OAuth access state of the gadget (see <divs> above).
          // If user hasn't approved access to data, provide a "Personalize this gadget" link
          // that contains the oauthApprovalUrl returned from makeRequest.
          //
          // If the user has opened the popup window but hasn't yet approved access, display
          // text prompting the user to confirm that s/he approved access to data.  The user
          // may not ever need to click this link, if the gadget is able to automatically
          // detect when the user has approved access, but showing the link gives users
          // an option to fetch their data even if the automatic detection fails.
          //
          // When the user confirms access, the fetchData() function is invoked again to
          // obtain and display the user's data.
          function showOneSection(toshow) {
            var sections = [ 'main', 'approval', 'waiting' ];
            for (var i=0; i < sections.length; ++i) {
              var s = sections[i];
              var el = document.getElementById(s);
              if (s === toshow) {
                el.style.display = "block";
              } else {
                el.style.display = "none";
              }
            }
          }

          // Process returned JSON feed to display data.
          function showResults(result) {
            showOneSection('main');

            var titleElement = document.createElement('div');
            var nameNode = document.createTextNode(result.description);
            document.getElementById("main").appendChild(nameNode);
            document.getElementById("main").appendChild(document.createElement("br"));


            var bodyNode = document.createElement("div");
            bodyNode.innerHTML = result.table;
            document.getElementById("main").appendChild(bodyNode);
          }

          // Invoke makeRequest() to fetch data from the service provider endpoint.
          // Depending on the results of makeRequest, decide which version of the UI
          // to ask showOneSection() to display. If user has approved access to his
          // or her data, display data.
          // If the user hasn't approved access yet, response.oauthApprovalUrl contains a
          // URL that includes a Google-supplied request token. This is presented in the
          // gadget as a link that the user clicks to begin the approval process.
          function fetchData() {
            var params = {};
            url = "http://localhost:8070/rest/gadget/1.0/issueTable/jql?jql=";
            url = url + escape("assignee = currentUser() AND resolution = unresolved ORDER BY priority DESC, created ASC");

            params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.JSON;
            params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.OAUTH;
            params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET;

            gadgets.io.makeRequest(url, function (response) {
              if (response.oauthApprovalUrl) {
                // Create the popup handler. The onOpen function is called when the user
                // opens the popup window. The onClose function is called when the popup
                // window is closed.
                var popup = shindig.oauth.popup({
                  destination: response.oauthApprovalUrl,
                  windowOptions: null,
                  onOpen: function() { showOneSection('waiting'); },
                  onClose: function() { fetchData(); }
                });
                // Use the popup handler to attach onclick handlers to UI elements.  The
                // createOpenerOnClick() function returns an onclick handler to open the
                // popup window.  The createApprovedOnClick function returns an onclick
                // handler that will close the popup window and attempt to fetch the user's
                // data again.
                var personalize = document.getElementById('personalize');
                personalize.onclick = popup.createOpenerOnClick();
                var approvaldone = document.getElementById('approvaldone');
                approvaldone.onclick = popup.createApprovedOnClick();
                showOneSection('approval');
              } else if (response.data) {
                showOneSection('main');
                showResults(response.data);
              } else {
                // The response.oauthError and response.oauthErrorText values may help debug
                // problems with your gadget.
                var main = document.getElementById('main');
                var err = document.createTextNode('OAuth error: ' +
                  response.oauthError + ': ' + response.oauthErrorText);
                main.appendChild(err);
                showOneSection('main');
              }
            }, params);
          }
          // Call fetchData() when gadget loads.
          gadgets.util.registerOnLoadHandler(fetchData);
        </script>



    ]]>
  </Content>

Проверьте полученный XML-файл в jql-gadget-step3.xml.

Шаг 6. Обновите гаджет на сервере.

  1. Выполните шаги, описанные выше в разделе «Шаг 4», чтобы добавить эту версию гаджета к вашему экземпляру confluence и добавить его на страницу для тестирования.
  2. Если вы внесете изменения в xml-файл, вам может потребоваться перезапустить Confluence, чтобы забрать изменения.

Проблема кэширования гаджета

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

  • В Confluence вам необходимо перезапустить Confluence или запустить его в режиме разработки.
  • В iGoogle вы можете использовать гаджет Google «Мои гаджеты», который позволяет отключить кеширование для определенных гаджетов.

Когда вы протестируете гаджет, вы увидите сообщение об ошибке «OAuth error: consumer_key_unknown». Это указывает на то, что OAuth не был настроен между JIRA и Confluence.

Шаг 7. Настройка OAuth

  1. Чтобы настроить OAuth, войдите в JIRA в качестве администратора.
  2. Прокрутите страницу вниз до раздела «Система» параметров администрирования и нажмите «OAuth»,
  3. Нажмите «Добавить пользователя OAuth».ы сделаем это на следующем шаге.
  4. Введите «http: // localhost: 8080 / confluence» в поле «URL-адрес потребительской базы».
  5. Нажмите «Добавить»
  6. Если вы нажмете на нового пользователя, вы увидите, что он был настроен с помощью секретного ключа, который позволяет запросам OAuth между двумя серверами.

Шаг 8. Проверка рабочего гаджета на странице Confluence

После настройки OAuth теперь вы можете авторизовать гаджет для использования в Confluence.

  1. Перезагрузите страницу, содержащую гаджет.
  2. Нажмите ссылку «Авторизовать этот гаджет»
  3. Нажмите кнопку «Утвердить доступ»
  4. Просмотр списка задач

Шаг 9. Сделайте гаджет лучше.

Поскольку гаджет - это просто HTML, Javascript и CSS, вы можете изменить внешний вид гаджета, добавив в файл CSS. Гораздо больше можно сделать, чем это, но добавление нескольких классов делает гаджет намного лучше.


      <style>
            #issuetable {margin:0 0 0.25em;width:100%;}
            #issuetable .issuetype {width:1%;}
            td.colHeaderLink {
                font-family:Arial,Helvetica,sans-serif;
                font-size:12px;
                white-space:nowrap;
            }
            .grid, .bordered {
                background-color:#FCFCFC;
                border:1px solid #D2D2D2;
                border-collapse:collapse;
                margin-bottom:0.5em;
                margin-top:0.5em;
            }
            .grid th, .grid td {
                border:1px solid #D2D2D2;
                padding:4px;
                vertical-align:top;
            }

        </style>

Проверьте полученный XML-файл в jql-gadget-step4.xml

Поздравляю, вот и все

Ваш гаджет завершен. Есть шоколад!

Следующие шаги

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

  • Интернационализация вашего гаджета
  • Упаковка вашего гаджета в качестве плагина Atlassian

По материалам Atlassian JIRA  Server Developer Writing a JQL standalone gadget