Como usar soy, requirejs, backbone js em plugins para o Atlassian Jira



Neste artigo, desenvolveremos um plug-in que salvará as configurações do plug-in no Jira. Usaremos as bibliotecas soy, requirejs, backbone js para exibir a interface do usuário. Soja, requirejs, backbone js são bibliotecas integradas no Jira.

O objetivo do artigo é mostrar como você pode usar as ferramentas internas do Jira para desenvolver uma interface com o usuário.

O plugin desenvolvido conterá um módulo de trabalho na web para salvar os parâmetros do plugin no Jira. Os parâmetros serão inseridos em duas telas (dois parâmetros em cada tela). Além disso, os parâmetros serão empacotados em json, que serão armazenados em Jira. O código fonte do plugin pode ser encontrado aqui .

Crie um esqueleto de plug-in


Abra o terminal e execute o comando abaixo:
atlas-create-jira-plugin

Responderemos às perguntas no terminal assim:

 Define value for groupId: : ru.matveev.alexey.jira.tutorial.webworkui Define value for artifactId: : webwork-soy-require-backbone Define value for version: 1.0.0-SNAPSHOT: : Define value for package: ru.matveev.alexey.jira.tutorial.webworkui: : Y: : Y 

Faça alterações no pom.xml


Depois de criar o esqueleto do plug-in, é necessário fazer alterações para que o atlassian-spring-scanner 2 funcione corretamente.

Instale a versão atlassian-spring-scanner na 2.0.0:

 <atlassian.spring.scanner.version>2.0.0</atlassian.spring.scanner.version> 

Altere o escopo da dependência atlassian-spring-scanner-annotation de compile para fornecido:

 <dependency> <groupId>com.atlassian.plugin</groupId> <artifactId>atlassian-spring-scanner-annotation</artifactId> <version>${atlassian.spring.scanner.version}</version> <scope>provided</scope> </dependency> 

Remova a dependência atlassian-spring-scanner-runtime.

Crie um serviço para receber e salvar configurações de plugins


Primeiro, crie uma interface para gerenciar as configurações do plug-in.

src / main / java / ru / matveev / alexey / jira / tutorial / webworkui / api / PluginSettingService.java
 package ru.matveev.alexey.jira.tutorial.webworkui.api; public interface PluginSettingService { String getConfigJson(); void setConfigJson(String json); } 


Agora vamos fazer a implementação da interface.

src / main / java / ru / matveev / alexey / jira / tutorial / webworkui / impl / PluginSettingServiceImpl.java
 package ru.matveev.alexey.jira.tutorial.webworkui.impl; import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; import com.atlassian.sal.api.pluginsettings.PluginSettings; import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; import ru.matveev.alexey.jira.tutorial.webworkui.api.PluginSettingService; import javax.inject.Inject; import javax.inject.Named; @Named public class PluginSettingServiceImpl implements PluginSettingService { public final PluginSettings pluginSettings; private static final String PLUGIN_STORAGE_KEY = "ru.matveev.alexey.jira.tutorial.webworkui."; private static final String CONFIG_JSON = "configjson"; @Inject public PluginSettingServiceImpl(@ComponentImport PluginSettingsFactory pluginSettingsFactory) { this.pluginSettings = pluginSettingsFactory.createGlobalSettings(); } private void setSettingValue(String settingKey, String settingValue) { this.pluginSettings.put(PLUGIN_STORAGE_KEY + settingKey, settingValue != null?settingValue:""); } private String getSettingValue(String settingKey) { return pluginSettings.get(PLUGIN_STORAGE_KEY + settingKey) != null?pluginSettings.get(PLUGIN_STORAGE_KEY + settingKey).toString():""; } @Override public String getConfigJson() { return getSettingValue(CONFIG_JSON); } @Override public void setConfigJson(String json) { setSettingValue(CONFIG_JSON, json); } } 


Os métodos getConfigJson e setConfigJson são responsáveis ​​por receber e salvar o parâmetro no formato json.

Crie um trabalho na web para gerenciar as configurações do plugin


Abra o terminal na pasta do plugin e execute o comando abaixo:
create-atlas-jira-plugin-module

Respondemos às perguntas no terminal da seguinte maneira:

 Choose a number (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34): 31 Enter Plugin Module Name My Webwork Module: : Config Show Advanced Setup? (Y/y/N/n) N: : Y Module Key config: : webwork-config Module Description The Config Plugin: : i18n Name Key config.name: : i18n Description Key config.description: : Enter Action Classname MyActionClass: : ConfigWebwork Enter Package Name ru.matveev.alexey.jira.tutorial.webworkui.jira.webwork: :Enter Alias ConfigWebwork: : Enter View Name success: : success.soy Enter Template Path /templates/webwork-config/configwebwork/success.soy.vm: : /templates/webwork-config/configwebwork/success.soy Add Another View? (Y/y/N/n) N: : N Add Another Action? (Y/y/N/n) N: : N Add Another Plugin Module? (Y/y/N/n) N: : N 

Como resultado, o arquivo src / main / java / ru / matveev / alexey / jira / tutorial / webworkui / jira / webwork / ConfigWebwork.java será criado. Este arquivo precisa ser alterado assim:

src / main / java / ru / matveev / alexey / jira / tutorial / webworkui / jira / webwork / ConfigWebwork.java
 package ru.matveev.alexey.jira.tutorial.webworkui.jira.webwork; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.atlassian.jira.web.action.JiraWebActionSupport; import ru.matveev.alexey.jira.tutorial.webworkui.api.PluginSettingService; import javax.inject.Inject; public class ConfigWebwork extends JiraWebActionSupport { private static final Logger log = LoggerFactory.getLogger(ConfigWebwork.class); private final PluginSettingService pluginSettingService; private String configJson; @Inject public ConfigWebwork(PluginSettingService pluginSettingService) { this.pluginSettingService = pluginSettingService; } @Override public String execute() throws Exception { super.execute(); return SUCCESS; } public void doSave() { pluginSettingService.setConfigJson(configJson); } @ActionViewData public String getConfigJson() { return pluginSettingService.getConfigJson().isEmpty()?"{}":pluginSettingService.getConfigJson(); } public void setConfigJson(String json) { this.configJson = json; } } 


A anotação @ActionViewData é necessária para que o parâmetro configJson esteja disponível no modelo soy.

Crie uma seção da web e um item da web


Adicionamos webwork. Agora adicione o item de menu a partir do qual o webwork será iniciado.
Abra o terminal e execute o seguinte comando:
create-atlas-jira-plugin-module

Respondemos às perguntas da seguinte maneira:

 Choose a number (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34): 30 Enter Plugin Module Name My Web Section: : Webwork Config Section Enter Location (eg system.admin/mynewsection): admin_plugins_menu Show Advanced Setup? (Y/y/N/n) N: : N Add Another Plugin Module? (Y/y/N/n) N: : Y Choose a number (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34): 25 Enter Plugin Module Name My Web Item: : Webwork Config Item Enter Section (eg system.admin/globalsettings): admin_plugins_menu/webwork-config-section Enter Link URL (eg /secure/CreateIssue!default.jspa): /secure/ConfigWebwork.jspa? Show Advanced Setup? (Y/y/N/n) N: : N Add Another Plugin Module? (Y/y/N/n) N: : N 

Como resultado, criamos um item de menu na página Complementos.

Crie um modelo de soja


Detalhes sobre modelos de soja podem ser encontrados aqui .

Vamos criar um arquivo
src / main / recursos / modelos / webwork-config / configwebwork / success.soy.

src / main / recursos / modelos / webwork-config / configwebwork / success.soy
 {namespace webwork.config} /** * This template is needed for drawing the formview. */ {template .formview} {@param configJson: string} {webResourceManager_requireResource('ru.matveev.alexey.jira.tutorial.webworkui.webwork-soy-require-backbone:webwork-soy-require-backbone-resources')} <html> <head> <meta charset="utf-8"/> <meta name="decorator" content="atl.admin"> <meta name="admin.active.section" content="admin_plugins_menu/telegram-config-section"> <meta name="admin.active.tab" content="telegram-general-config-item"> <title>my page page</title> </head> <body> <div id="container"> <form class="aui" action="ConfigWebwork!save.jspa" method="POST"> <div class="field-group"> <label for="configJson">Json</label> <input class="text long-field" type="text" id="configJson" name="configJson" placeholder="Json String" value="{$configJson}"> <div class="description">the configJson Parameter</div> </div> <div class="buttons-container"> <div class="buttons"> <input class="button submit" type="submit" value="Save" id="config-save-button"> <a class="cancel" href="#">Cancel</a> </div> </div> </form> </div> </body> </html> {/template} 


No arquivo atlassian-plugin.xml, adicione um link ao modelo de soja criado na tag de recurso da web:

 <resource type="soy" name="webwork-config" location="/templates/webwork-config/configwebwork/success.soy"/> 

Agora faremos alterações no atlassian-plugin.xml para que, quando acessarmos o trabalho na web, o modelo de soja criado seja exibido:

 <view name="success" type="soy">:webwork-soy-require-backbone-resources/webwork.config.formview</view> 

webwork-soy-require-backbone-resources é o atributo name na tag web-resource, onde adicionamos um link ao nosso modelo de soja.

webwork.config.formview - espaço para nome e nome do modelo no arquivo soy.

Plug-in de teste


Abra o terminal na pasta do plugin e execute o seguinte comando:
atlas-run

Após a inicialização do Jira, acesse o navegador usando o seguinte link:

localhost : 2990 / jira / secure / ConfigWebwork.jspa

A tela ficará assim:



Você pode tentar inserir dados no campo Json e salvar. O trabalho na web funciona.
Agora precisamos garantir que haja duas telas para preencher os parâmetros e, na última tela, o botão Salvar deve converter todos os parâmetros para o formato json e salvar nas configurações do plug-in.

Para controlar a lógica de mover telas e converter parâmetros para o formato json, usaremos o backbone js. Você pode ler sobre backbone js aqui .

Criar um modelo de backbone


src / main / recursos / js / webwork-config-model.js
define ('webwork / config / model', [
'jquery',
'espinha dorsal',
'sublinhado'
], função ($, Backbone, _) {
var WebConfigModel = Backbone.Model.extend ({
padrões: {
parâmetro1: '',
parâmetro2: '',
parâmetro3: '',
parâmetro4: ''
}
});
retornar {
Modelo: WebConfigModel
};
})

Para que o modelo esteja disponível ao carregar o modelo soy, o arquivo com o modelo deve ser adicionado a atlassian-plugin.xml na tag de recurso da web:

 <resource type="download" name="webwork-config-model.js" location="/js/webwork-config-model.js"/> 

Criar uma visualização de backbone


Eu escrevi comentários no código para pontos importantes.

src / main / recursos / js / webwork-config-view.js
// define é uma diretiva requirejs e define o modelo como um módulo webwork / config / view. Isso nos permite definir dependências em outros arquivos no modelo.
define ('webwork / config / view', [
'jquery',
'espinha dorsal',
'sublinhado'
], função ($, Backbone, _) {
"Use estrito";
var AppView = Backbone.View.extend ({
eventos: {
"Clique em # config-save-button": "saveConfig",
"Clique em # próximo botão": "nextButton",
"Clique em # botão voltar": "prevButton"

}
// função que funciona com o botão Salvar. Salva parâmetros da tela no modelo e converte os parâmetros no formato json
saveConfig: function () {
this.model.set ("parameter3", $ ("# parameter3"). val ());
this.model.set ("parameter4", $ ("# parameter4"). val ());
$ ("# configJson"). val (JSON.stringify (this.model));
}
// função que funciona com o botão Avançar na primeira tela. Salva os parâmetros da primeira tela no modelo e desenha uma segunda tela
nextButton: function () {
this.model.set ("parameter1", $ ("# parameter1"). val ());
this.model.set ("parameter2", $ ("# parameter2"). val ());
var template = webwork.config.page2 ({configJson: $ ("# configJson"). val (), parâmetro3: this.model.get ('parameter3'), parâmetro4: this.model.get ('parameter4')} );
$ ("# container"). replaceWith (template);
$ ("# configJson"). val (JSON.stringify (this.model));
}
// função que funciona pelo botão Voltar na segunda tela. Salva os parâmetros da segunda tela no modelo e desenha a primeira tela
prevButton: function () {
this.model.set ("parameter3", $ ("# parameter3"). val ());
this.model.set ("parameter4", $ ("# parameter4"). val ());
var template = webwork.config.page1 ({configJson: $ ("# configJson"). val (), parâmetro1: this.model.get ('parameter1'), parâmetro2: this.model.get ('parameter2')} );
$ ("# container"). replaceWith (template);
$ ("# configJson"). val (JSON.stringify (this.model));
}
initialize: function () {
this.render ();
}
render: function () {
var template = webwork.config.page1 ({configJson: $ ("# configJson"). val (), parâmetro1: this.model.get ('parameter1'), parâmetro2: this.model.get ('parameter2')} );
$ ("# container"). replaceWith (template);
}
// este é um link para o contêiner principal. A visualização capturará todos os eventos dos elementos abaixo desse elemento.
el: '#maincontainer'
});
retornar {
Exibir: AppView
};
})

Para que a visualização esteja disponível ao carregar o modelo soy, o arquivo com a visualização deve ser adicionado a atlassian-plugin.xml na tag de recurso da web:

 <resource type="download" name="webwork-config-view.js" location="/js/webwork-config-view.js"/> 

Crie um arquivo js para customizar o modelo de backbone e visualizar


src / main / recursos / js / webwork-soy-require-backbone.js
require ([
'webwork / config / view',
'webwork / config / model',
'jquery',
'espinha dorsal',
'sublinhado'
], função (webworkConfigView, webworkConfigModel, $, Backbone, _) {
var webworkConfigModel = novo webworkConfigModel.Model (JSON.parse ($ ("# configJson"). val ()));
var actionsView = novo webworkConfigView.View ({model: webworkConfigModel});

})

Nosso arquivo js usa requirejs. A diretiva require permite garantir que o arquivo seja baixado somente após o download de todas as dependências. Definimos as seguintes dependências para nosso arquivo: webwork / config / view, webwork / config / model, consulta, backbone, sublinhado.

Adicione os parâmetros necessários para que os modelos de soja funcionem.


Na tag de recurso da web no arquivo atlassian-plugin.xml, adicione:

 <transformation extension="soy"> <transformer key="soyTransformer"/> </transformation> <resource name="success-soy.js" type="download" location="/templates/webwork-config/configwebwork/success.soy"/> 

Esses parâmetros permitem acessar o modelo de soja nos arquivos js.

Faça alterações no success.soy


Adicionei comentários a pontos importantes

src / main / recursos / modelos / webwork-config / configwebwork / success.soy
 {namespace webwork.config} /** *      webwork.   json .       page1.    ,   json    backbone model. */ {template .formview} {@param configJson: string} {webResourceManager_requireResource('ru.matveev.alexey.jira.tutorial.webworkui.webwork-soy-require-backbone:webwork-soy-require-backbone-resources')} <html> <head> <meta charset="utf-8"/> <meta name="decorator" content="atl.admin"> <meta name="admin.active.section" content="admin_plugins_menu/telegram-config-section"> <meta name="admin.active.tab" content="telegram-general-config-item"> <title>my page page</title> </head> <body> <div id="maincontainer"> <div id="container"> <input class="text long-field hidden" type="text" id="configJson" name="configJson" placeholder="Json String" value="{$configJson}"> </div> </div> </body> </html> {/template} /** *    .   parameter1  parameter2. */ {template .page1} {@param configJson: string} {@param parameter1: string} {@param parameter2: string} <div id="container"> <form class="aui"> <div class="field-group"> <label for="parameter1">Parameter 1</label> <input class="text long-field" type="text" id="parameter1" name="parameter1" placeholder="Parameter1 value" value="{$parameter1}"> <div class="description">Value of Parameter 1</div> </div> <div class="field-group"> <label for="parameter2">Parameter 2</label> <input class="text long-field" type="text" id="parameter2" name="parameter2" placeholder="Parameter2 value" value="{$parameter2}"> <div class="description">Value of Parameter 2</div> </div> <div class="field-group"> <input class="text long-field hidden" type="text" id="configJson" name="configJson" placeholder="Json String" value="{$configJson}"> </div> <div class="buttons-container"> <div class="buttons"> <a class="cancel" href="#">Cancel</a> <input class="button submit" type="submit" value="Next" id="next-button"> </div> </div> </form> </div> {/template} /** *    .   parameter3  parameter4. */ {template .page2} {@param configJson: string} {@param parameter3: string} {@param parameter4: string} <div id="container"> <form class="aui" action="ConfigWebwork!save.jspa" method="POST"> <div class="field-group"> <label for="parameter1">Parameter 3</label> <input class="text long-field" type="text" id="parameter3" name="parameter3" placeholder="Parameter3 value" value="{$parameter3}"> <div class="description">Value of Parameter 3</div> </div> <div class="field-group"> <label for="parameter4">Parameter 4</label> <input class="text long-field" type="text" id="parameter4" name="parameter4" placeholder="Parameter4 value" value="{$parameter4}"> <div class="description">Value of Parameter 4</div> </div> <div class="field-group"> <input class="text long-field hidden" type="text" id="configJson" name="configJson" placeholder="Json String" value="{$configJson}"> </div> <div class="buttons-container"> <div class="buttons"> <input class="button submit" type="submit" value="Back" id="back-button"> <input class="button submit" type="submit" value="Save" id="config-save-button"> </div> </div> </form> </div> {/template} 

Testando o aplicativo


Abra o terminal na pasta do plug-in e execute:

atlas-run

Após a inicialização do Jira, abra o navegador usando o link:

http://localhost:2990/jira/secure/ConfigWebwork.jspa

Você verá a seguinte tela:



Preencha os parâmetros e clique no botão Avançar. A seguinte tela será exibida:



Preencha os parâmetros 3 e 4 e clique no botão Salvar. Os parâmetros serão salvos no formato Json. Você pode clicar no botão Voltar e será direcionado para a primeira tela.

Nosso plugin funciona.

Source: https://habr.com/ru/post/pt415809/


All Articles