How to show banner when there is only reject reason from PR

Hello Experts ,
@khughes , @madamczak , @bturner , @mheemskerk

We are using Bitbucket Server 8.1.2 and few days planning to upgrading it 8.6.1. Am new to plugin development, I have a requirement as stated below.

Requirements:
we have enabled custom merge-check hook, which checks the pull-request and merge button is enabled if the checks are passed/accepted or reject with reason if the checks are failed/rejected as shown below.

image

Now there was a request to display this reject reasons as a banner in the pull request instead of the default warning from merge button.

I was able to figure it out how to display the warning message in banner as shown below

Am encountering two issues now,

  1. Am getting banner in other areas of the repository listing and repository view, which is not my end goal

  1. I need to refresh the PR every time if edited the description for any correction, Merge button warning is getting updated every time there change in the description dynamically. Need some suggestions how we can handle it.

Please suggest me how to overcome above mentioned issues.


Contex Manger code snippet: MyContextProvider.java

@Component
@Qualifier("mycontextprovider")
//public class MyContextProvider implements ContextProvider, MyBannerContextProvider {
public class MyContextProvider implements ContextProvider {
    private static final Logger LOGGER = LogManager.getLogger(MyContextProvider.class);
    private static String passingMessage = "";

    @Override
    public void init(Map<String, String> map) throws PluginParseException {
//        passingMessage = map.get("errorMessage");
    }

    public void setContextMap(Map<String, String> map) throws PluginParseException {
          passingMessage = map.get("errorMessage");
    }

    @Override
    public Map<String, Object> getContextMap(Map<String, Object> map) {
        ImmutableMap.Builder<String, Object> response = new ImmutableMap.Builder<String, Object>()
                .put("mcMessage", passingMessage);
        Map<String, String> resetMap = new HashMap<>();
        resetMap.put("errorMessage","");
        this.setContextMap(resetMap);
        return response.build();
    }
}

Java script: prmc.js

let close = false;

AJS.$(document).ready(function() {
    function refresh()
    {
        if ((AJS.$("#aui-dialog2-content").textContent!="undefined")&&(close!=true)){
            if (AJS.$("#aui-dialog2-content").textContent!=""){
                AJS.dialog2("#demo-warning-dialog").show();
            }
        }
    }
    setInterval(function()
    {
        refresh()
    }, 10000); //300000 is 5minutes in ms
});

AJS.toInit(function(){
    AJS.log('Main page JS Controller initializing ..., contextPath=' + AJS.contextPath());
    let close = false;
});

atlassian-plugin.xml

<?xml version="1.0" encoding="UTF-8"?>

<atlassian-plugin key="${atlassian.plugin.key}" name="${project.name}" plugins-version="2">
    <plugin-info>
        <description>${project.description}</description>
        <version>${project.version}</version>
        <vendor name="${project.organization.name}" url="${project.organization.url}"/>
        <param name="plugin-icon">images/pluginIcon.png</param>
        <param name="plugin-logo">images/pluginLogo.png</param>
    </plugin-info>

    <!-- add our web resources -->
    <web-resource key="pull-request-merge-check-resources" name="pull-request-merge-check Web Resources">
        <resource type="download" name="prmc.css" location="css/prmc.css"/>
        <resource type="download" name="prmc.js" location="js/prmc.js"/>
        <resource type="download" name="images" location="images"/>
        <dependency>com.atlassian.auiplugin:ajs</dependency>
        <dependency>com.atlassian.auiplugin:soy</dependency>
        <dependency>com.atlassian.auiplugin:aui-banner</dependency>
        <context>bitbucket.page.pullRequest.detail</context>
    </web-resource>

    <web-panel key="prmc-web-panel-banner" weight="1000" location="bitbucket.web.repository.banner">
        <description>
            Web panel component used to handle the display of the pull request banner
        </description>
        <context-provider class="com.viavi.wireless.bitbucket.provider.MyContextProvider" />
        <resource name="view" type="soy" location="${atlassian.plugin.key}:prmc-soy/bitbucket.plugin.popup.myTemplate1"/>
    </web-panel>

    <client-resource key="prmc-soy" name="Plugin Soy Templates">
        <directory location="/templates">
            <include>/**/*.soy</include>
        </directory>
        <context>prmc</context>
        <!--        very important to include this line here !!!-->
        <dependency>com.atlassian.bitbucket.server.bitbucket-web:server-soy-templates</dependency>
    </client-resource>

    <repository-hook key="pull-request-merge-check-hook" name="Pull Request Merge Check Hook"
                     class="bitbucket.hook.prmc.PullRequestMergeCheckHook">
        <description key="pull-request-merge-check-hook.description">
            Plugin to validate the pre-sub link in the Pull Request Description</description>
        <scopes>
            <scope>project</scope>
            <scope>repository</scope>
        </scopes>
        <config-form name="Pull Request Merge Check" key="pull-request-merge-check-hook-config">
            <view>bitbucket.hook.prmc.pullrequestmergecheckhook.view</view>
            <directory location="/static/"/>
        </config-form>
    </repository-hook>
</atlassian-plugin>

soy template to render : prmc.soy
{namespace bitbucket.plugin.popup}

/**
 * This is the template of the popup window of the plugin.
 *
 * @param mcMessage The message to display in the banner
 */
{template .myTemplate1}
    <body>
        <section id="demo-banner-dialog" role="banner" class="ScrollStyle" aria-hidden="true">
            <header id="header">
                <div id="div-message" class="aui-banner aui-banner-error">
                <p>{$mcMessage}</p>
                </div>
            </header>
        </section>
    </body>
{/template}

PRMC class: PullRequestMergeCheckHook.java


@Qualifier("mycontextprovider")
private MyContextProvider bannerContextProvider;
				
@Autowired
public PullRequestMergeCheckHook(
	  <properiteiry code>
	, MyContextProvider bannerContextProvider
) {
	<properiteiry code>
	this.bannerContextProvider = bannerContextProvider;
}

//sending the wraning message to banner using contex provider
Map<String, String> map = new HashMap<>();
map.put("errorMessage", validation.getDetails());
this.bannerContextProvider.setContextMap(map);
//sending the wraning message to banner using contex provider
RepositoryHookResult.rejected(validation.getDetails(), validation.getSummary());

Kindly provide any suggestion for addressing below mentioned issues

  1. Am getting banner in other areas of the repository listing and repository view, which is not my end goal
  2. I need to refresh the PR every time if edited the description for any correction, Merge button warning is getting updated every time there change in the description dynamically.

Thanks!
Natesan S

Hi @NatesanS,

What you are trying to accomplish is a non-standard UX for the merge check.

If you want to hide that banner element by default you can add the hidden attribute to the HTML element:

<section hidden id="demo-banner-dialog" role="banner" class="ScrollStyle" aria-hidden="true">

Now, when you are on the Pull Request page you can un-hide it in some way using JavaScript e.g.:

// Check if you are on the pull request page and if the banner should be visisble
const bannerEl = document.querySelector('#demo-banner-dialog');
if (bannerEl) {
    bannerEl.removeAttribute('hidden');
}

Thanks,
Maciej Adamczak
Atlassian Developer

1 Like

@madamczak ,

I want to update web-panel when ever my contexprovider is getting updated from plugin code. Lets say we will update that every 3 mins once - How I can update web panel to get the latest value from contextprovider.

Thanks!
Natesan S

@NatesanS I’m not aware of any built-in mechanism for that, but you can try another solution.

I think what you want is to implement a polling mechanism with JS that will call some REST endpoint you added inside the plugin. Once you have a response from the REST end-point, you can update the web-panel manually using JS.